How can I fetch emails on Android?

1k views Asked by At

I'm trying to develop an app that fetches emails from a POP3 server that is not Google and I'm facing many problems.
I'm using JavaMail library and following TutorialsPoint tutorial. Their example for pop3 works fine on Eclipse/desktop but when I move the code on Android it never works and I'm frustrated.
In logcat I get all heaps of errors first of which states that

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

Is there a way that I can fix the AsyncTask to work correctly?

Also, is there a way that I can do something like this not using a professional app like K-9 Mail?

The code if somebody is interested:

 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());

    }

}
2

There are 2 answers

1
Daniel Nugent On BEST ANSWER

It looks like you are not using the AsyncTask correctly, especially seeing that you have a GO() method that directly calls doInBackground(). Remove the GO() method, there is no need for it.

The proper way to execute an AsyncTask is to use the execute() method, which calls doInBackground() and runs it on a worker thread, which will eliminate the NetworkOnMainThreadException runtime errors that you are getting currently.

So, in addition to using a library that is specific to Android, fix your AsyncTask so that it actually runs the doInBackground() method in a worker thread instead of the main UI thread.

In general it's better practice to use generics and varargs rather than just having doInBackground() take a Object[] as a parameter. It would also be useful to be able to pass in the username and password each time you execute the AsyncTask, so make it take a String varargs parameter.

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;
    }
}

Then, to properly execute the AsyncTask, use the execute() method, and pass in a username and password:

 //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);

Also, note that any UI related code will need to be placed in onPostExecute(), since all UI tasks need to be executed on the main UI thread in Android.

For more general info on AsyncTasks, there is a lot of good info in this question and the answers posted

1
isma3l On

Try with this lib https://code.google.com/p/javamail-android/.

Don't know the exact status of the lib but they have a good example in this blog (http://www.jondev.net/articles/Sending_Emails_without_User_Intervention_%28no_Intents%29_in_Android) and they say

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