如何获取 Android 上的电子邮件?

How can I fetch emails on Android?

我正在尝试开发一个从非 Google 的 POP3 服务器获取电子邮件的应用程序,但我遇到了很多问题。
我正在使用 JavaMail 库并遵循 TutorialsPoint 教程。他们的 pop3 示例在 Eclipse/desktop 上运行良好,但是当我在 Android 上移动代码时,它永远不会运行,我很沮丧。
在 logcat 中,我得到了所有错误,其中第一个指出

W/System.err﹕ android.os.NetworkOnMainThreadException even though I'm using AsyncTask (probably not correctly).

有什么方法可以让 AsyncTask 正常工作吗?

此外,有没有一种方法可以让我不使用像 K-9 Mail 这样的专业应用程序来做这样的事情?

代码如果有人感兴趣:

 public class FetchPop extends AsyncTask{

    public static void fetch(String pop3Host, String storeType, String user,
                             String password) {
        try {
            // create properties field
            Properties properties = new Properties();
            properties.put("mail.store.protocol", "pop3");
            properties.put("mail.pop3.host", pop3Host);
            properties.put("mail.pop3.port", "995");
            properties.put("mail.pop3.starttls.enable", "true");
            Session emailSession = Session.getDefaultInstance(properties);
            // emailSession.setDebug(true);

            // create the POP3 store object and connect with the pop server
            Store store = emailSession.getStore("pop3s");

            store.connect(pop3Host, user, password);

            // create the folder object and open it
            Folder emailFolder = store.getFolder("INBOX");
            emailFolder.open(Folder.READ_ONLY);

            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    System.in));

            // retrieve the messages from the folder in an array and print it
            Message[] messages = emailFolder.getMessages();
            Log.d("No. messages:", messages.length + ""); //just the number at first


/*for (int i = 0; i < messages.length; i++) {
                Message message = messages[i];
                writePart(message);
                String line = reader.readLine();
                if ("YES".equals(line)) {
                    message.writeTo(System.out);
                } else if ("QUIT".equals(line)) {
                    break;
                }
            }*/
            // close the store and folder objects
            emailFolder.close(false);
            store.close();

        } catch (NoSuchProviderException e) {
            e.printStackTrace();
        } catch (MessagingException e) {
            e.printStackTrace();
        } /*catch (IOException e) {
            e.printStackTrace();
        }*/ catch (Exception e) {
            e.printStackTrace();
        }
    }


        @Override
        protected Object doInBackground(Object[] params) {
            String host = "pop.gmail.com";// I tried google's pop 
            String mailStoreType = "pop3";
            String username =
                    "myusername";// change accordingly
            String password = "notmyrealpass";// change accordingly

            //Call method fetch
            fetch(host, mailStoreType, username, password);
            Log.d("mytag","done!");
            return null;
        }

    public void GO() {
        doInBackground(null);
    }





    /*
    * This method checks for content-type
    * based on which, it processes and
    * fetches the content of the message
    */
    public static void writePart(Part p) throws Exception {
        if (p instanceof Message)
            //Call methos writeEnvelope
            writeEnvelope((Message) p);

       /* System.out.println("----------------------------");
        System.out.println("CONTENT-TYPE: " + p.getContentType());*/

        //check if the content is plain text
        if (p.isMimeType("text/plain")) {
            System.out.println("This is plain text");
            System.out.println("---------------------------");
            System.out.println((String) p.getContent());
        }
        //check if the content has attachment
        else if (p.isMimeType("multipart/*")) {
            System.out.println("This is a Multipart");
            System.out.println("---------------------------");
            Multipart mp = (Multipart) p.getContent();
            int count = mp.getCount();
            for (int i = 0; i < count; i++)
                writePart(mp.getBodyPart(i));
        }
        //check if the content is a nested message
        else if (p.isMimeType("message/rfc822")) {
            System.out.println("This is a Nested Message");
            System.out.println("---------------------------");
            writePart((Part) p.getContent());
        }
        //check if the content is an inline image
        else if (p.isMimeType("image/jpeg")) {
            System.out.println("--------> image/jpeg");
            Object o = p.getContent();

            InputStream x = (InputStream) o;
            // Construct the required byte array
            int i;
            byte[] bArray = new byte[0];
            System.out.println("x.length = " + x.available());
            while ((i = (int) ((InputStream) x).available()) > 0) {
                int result = (int) (((InputStream) x).read(bArray));
                if (result == -1)
                    i=0;
                bArray = new byte[x.available()];

                break;
            }
            FileOutputStream f2 = new FileOutputStream("/tmp/image.jpg");
            f2.write(bArray);
        }
        else if (p.getContentType().contains("image/")) {
            System.out.println("content type" + p.getContentType());
            File f = new File("image" + new Date().getTime() + ".jpg");
            DataOutputStream output = new DataOutputStream(
                    new BufferedOutputStream(new FileOutputStream(f)));
            com.sun.mail.util.BASE64DecoderStream test =
                    (com.sun.mail.util.BASE64DecoderStream) p
                            .getContent();
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = test.read(buffer)) != -1) {
                output.write(buffer, 0, bytesRead);
            }
        }
        else {
            Object o = p.getContent();
            if (o instanceof String) {
                System.out.println("This is a string");
                System.out.println("---------------------------");
                System.out.println((String) o);
            }
            else if (o instanceof InputStream) {
                System.out.println("This is just an input stream");
                System.out.println("---------------------------");
                InputStream is = (InputStream) o;
                is = (InputStream) o;
                int c;
                while ((c = is.read()) != -1)
                    System.out.write(c);
            }
            else {
                System.out.println("This is an unknown type");
                System.out.println("---------------------------");
                System.out.println(o.toString());
            }
        }

    }
    /*
    * This method would print FROM,TO and SUBJECT of the message
    */
    public static void writeEnvelope(Message m) throws Exception {
        System.out.println("This is the message envelope");
        System.out.println("---------------------------");
        Address[] a;

        // FROM
        if ((a = m.getFrom()) != null) {
            for (int j = 0; j < a.length; j++)
                System.out.println("FROM: " + a[j].toString());
        }

        // TO
        if ((a = m.getRecipients(Message.RecipientType.TO)) != null) {
            for (int j = 0; j < a.length; j++)
                System.out.println("TO: " + a[j].toString());
        }

        // SUBJECT
        if (m.getSubject() != null)
            System.out.println("SUBJECT: " + m.getSubject());

    }

}

试试这个库 https://code.google.com/p/javamail-android/

不知道库的确切状态,但他们在这个博客中有一个很好的例子 (http://www.jondev.net/articles/Sending_Emails_without_User_Intervention_%28no_Intents%29_in_Android),他们说

"this is a special version of the JavaMail API, which was written specifically for Android."

看起来您没有正确使用 AsyncTask,尤其是看到您有一个直接调用 doInBackground()GO() 方法。去掉GO()方法,不需要了

执行 AsyncTask 的正确方法是使用 execute() 方法,该方法调用 doInBackground() 并在工作线程上运行它,这将消除 NetworkOnMainThreadException 运行时错误你现在得到。

因此,除了使用特定于 Android 的库之外,修复您的 AsyncTask 以便它实际上在工作线程而不是主线程中运行 doInBackground() 方法 UI 线程。

一般来说,更好的做法是使用泛型和可变参数,而不是让 doInBackground()Object[] 作为参数。 每次执行 AsyncTask 时都能够传递用户名和密码也很有用,因此让它采用 String varargs 参数。

public class FetchPop extends AsyncTask<String, Void, Void> {

    @Override
    protected Void doInBackground(String... params) {
        String host = "pop.gmail.com";// I tried google's pop 
        String mailStoreType = "pop3";

        String username = params[0]; //passed in through the execute() method      
        String password = params[1]; //passed in through the execute() method

        //Call method fetch
        fetch(host, mailStoreType, username, password);
        Log.d("mytag", "done!");
        return null;
    }
}

然后,要正确执行AsyncTask,使用execute()方法,并传入用户名和密码:

 //First get the username and password from the user through the UI
 String user =  "myusername"; // change accordingly
 String pass = "notmyrealpass"; // change accordingly
 new FetchPop().execute(user, pass);

此外,请注意任何 UI 相关代码都需要放在 onPostExecute() 中,因为所有 UI 任务都需要在主 UI 线程上执行在 Android.

有关 AsyncTasks 的更多一般信息,this question and the answers posted

中有很多有用的信息