Sending E-mails from Android

Standard

Getting Started

As a user, have you ever seen an android app that sends you interesting information?. As a developer, have you ever feel you would like to send valuable info to your users through their email with information?… Well, this is a commonplace problem among android applications. A first approach of sending emails (and the easiest) is to use the built-in Email apps installed in our device. However, this is only useful in some cases. When we need to send information with no user input/intervention this heads to a little harder approach, Pure code!, sending everything “behind the scenes”.

Intents Approach

Of course there is an email “intent” utility that you could use almost in all devices when we are developing an app. However, this intent allows the user to explicitly modify data before sending the email, which is not always the desired functionality. For instance, we will not extensively describe this functionality here, but you may see how it works in the next images:

i1         i2

As you can see, the first step with this functionality is to let you choose your email provider to send it (e.g. gmail, hotmail, E-mail, etc). Then, the user is free to modify the email subject, content, to-list, attach extra files or even delete them, which results in a problem when you need to send private information to user, like a new ranking achieved, or earned points, a transaction confirmation, etc.

Behind the Scenes Approach

This is maybe the nicest way to send a mail from android to our valuable users. But, do we really know to write down thousands and thousand of code lines??? This does not sound good. Fortunately, there is a nice and robust API for the Java language which allow us to send emails with not much effort. This API is known as JavaMail

In my experience, when dealing with android, which uses Java as programming language, i wrongly though “ooh, as android uses Java, all which works in java may also work in android”. And yes, you’re right… this is not always true. After looking for several minutes, i found a good samaritan forum which gives us the needed libraries to work with JavaMail from android nice and easy with no problems. Keep in mind, we will use a Gmail authentication in this tutorial.

In order to follow this tutorial, the first step is to download the needed libraries (.jar files) found in the next links:

 After downloading these files, just import them to your project and we’re ready to go!

Start Coding!

We will concentrate all the functionality we need in a single class (as we must always do). So, the first step is to create a new class, lets call it MailService, which will extend from javax.mail.Authenticator.

public class MailService extends javax.mail.Authenticator {
}

The most important attributes our class must have, are of course: subject, body, user, password, and the to-list. So, lets create them.

private String _user;
private String _pass;

private String[] _to;
private String _from;

private String _subject;
private String _body;

There are several fields our mail client need, there are: a port, host, a socket factory port and the smtp authentication mode.

private String _port;
private String _sport;

private String _host;

private boolean _auth;

private boolean _debuggable;

private Multipart _multipart;

We will initialize our fields from a main constructor, just as follows:

public MailService(String usr, String pswd, String from, String sub, String bod) {
    _host = "smtp.gmail.com"; // default smtp server
    _port = "465"; // default smtp port
    _sport = "465"; // default socketfactory port

    _user = usr;
    _pass = pswd; // password
    _from = from; // email sent from
    _subject = sub; // email subject
    _body = bod; // email body

    _debuggable = false; // debug mode on or off - default off
    _auth = true; // smtp authentication - default on

    _multipart = new MimeMultipart();

    // There is something wrong with MailCap, javamail can not find a handler for the multipart/mixed part, so this bit needs to be added.
    MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
    mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
    mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
    mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
    mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
    mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
    CommandMap.setDefaultCommandMap(mc);
}

Now we have our class configured and ready to start sending emails. But, how do we use it? With the next magic function…

public boolean send() throws Exception {
    Properties props = _setProperties();

    if(!_user.equals("") && !_pass.equals("") && _to.length > 0 && !_from.equals("") && !_subject.equals("") && !_body.equals("")) {
        Session session = Session.getInstance(props, this);

        final MimeMessage msg = new MimeMessage(session);

        msg.setFrom(new InternetAddress(_from));

        InternetAddress[] addressTo = new InternetAddress[_to.length];
        for (int i = 0; i < _to.length; i++) {
            addressTo[i] = new InternetAddress(_to[i]);
        }
        msg.setRecipients(MimeMessage.RecipientType.TO, addressTo);

        msg.setSubject(_subject);
        msg.setSentDate(new Date());

        // setup message body
        BodyPart messageBodyPart = new MimeBodyPart();
        messageBodyPart.setText(_body);
        _multipart.addBodyPart(messageBodyPart);

        // Put parts in message
        msg.setContent(_multipart);

        Thread thread = new Thread(new Runnable(){
            @Override
            public void run() {
                try {
                    // send email
                    Transport.send(msg);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        thread.start();
        return true;
    } else {
        return false;
    }
}

The first thing to note here, is that we need to instantiate our class before start sending mails. A first validations start the function, which just look for empty fields (which may or may not happen). A Session object is instantiated, its job is to authenticate our account and manage it. After this, a MimeMessage object is instantiated, here is where we begin to construct our mail itself. Finally, note the new thread created to send the email. If we use no threads here, the android app is going to crash since it is considered as a network task.

After some modifications, our final class is going to look like this:

import javax.activation.CommandMap;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.activation.MailcapCommandMap;
import javax.mail.BodyPart;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
public class MailService extends javax.mail.Authenticator {
    private String _user;
    private String _pass;
    private String[] _to;
    private String _from;
    private String _port;
    private String _sport;
    private String _host;
    private String _subject;
    private String _body;
    private boolean _auth;
    private boolean _debuggable;
    private Multipart _multipart;
    public MailService(String usr, String pswd, String from, String sub, String bod) {
        _host = "smtp.gmail.com"; // default smtp server
        _port = "465"; // default smtp port
        _sport = "465"; // default socketfactory port
        _user = usr;
        _pass = pswd; // password
        _from = from; // email sent from
        _subject = sub; // email subject
        _body = bod; // email body
        _debuggable = false; // debug mode on or off - default off
        _auth = true; // smtp authentication - default on
        _multipart = new MimeMultipart();
        MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
        mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
        mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
        mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
        mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
        mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
        CommandMap.setDefaultCommandMap(mc);
    }
    public boolean send() throws Exception {
        Properties props = _setProperties();
        if(!_user.equals("") && !_pass.equals("") && _to.length > 0 && !_from.equals("") && !_subject.equals("") && !_body.equals("")) {
            Session session = Session.getInstance(props, this);
            final MimeMessage msg = new MimeMessage(session);
            msg.setFrom(new InternetAddress(_from));
            InternetAddress[] addressTo = new InternetAddress[_to.length];
            for (int i = 0; i < _to.length; i++) {
                addressTo[i] = new InternetAddress(_to[i]);
            }
            msg.setRecipients(MimeMessage.RecipientType.TO, addressTo);
            msg.setSubject(_subject);
            msg.setSentDate(new Date());
            // setup message body
            BodyPart messageBodyPart = new MimeBodyPart();
            messageBodyPart.setText(_body);
            _multipart.addBodyPart(messageBodyPart);
            // Put parts in message
            msg.setContent(_multipart);
            Thread thread = new Thread(new Runnable(){
                @Override
                public void run() {
                    try {
                        // send email
                        Transport.send(msg);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
            thread.start();
            return true;
        } else {
            return false;
        }
    }
    public void addAttachment(String filename) throws Exception {
        BodyPart messageBodyPart = new MimeBodyPart();
        DataSource source = new FileDataSource(filename);
        messageBodyPart.setDataHandler(new DataHandler(source));
        messageBodyPart.setFileName(filename);
        _multipart.addBodyPart(messageBodyPart);
    }
    @Override
    public PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication(_user, _pass);
    }
    private Properties _setProperties() {
        Properties props = new Properties();
        props.put("mail.smtp.host", _host);
        if(_debuggable) {
            props.put("mail.debug", "true");
        }
        if(_auth) {
            props.put("mail.smtp.auth", "true");
        }
        props.put("mail.smtp.port", _port);
        props.put("mail.smtp.socketFactory.port", _sport);
        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        props.put("mail.smtp.socketFactory.fallback", "false");
        return props;
    }
    public void set_to(String[] _to) {
        this._to = _to;
    }
}

Now lets consume our email class!! As easy as follows.

MailService m = new MailService("our.account@gmail.com", "password", "from.account@gmail.com", "Mail subject here!", "Mail body here!");

String [] toArr = {"to.account1@gmail.com","to.account2@gmail.com"...};
m.set_to(toArr);

if(m.send()) {
    Toast.makeText(this.getContext(), "Email was sent successfully.", Toast.LENGTH_LONG).show();
}else {
    Toast.makeText(this.getContext(), "Email was not sent.", Toast.LENGTH_LONG).show();
}

And that’s it, we have sent an email from our android app 🙂

Oh wait…. What is we need to attach a file in our email? Easy again! just use the addAttachement function from our class before sending the mail. Notice the function just receives the file’s path we need to send. Just like this:

m.addAttachment("path/to/my/file/file_name");

Many attachments?, many calls to the function.

Leave a Reply

Your email address will not be published. Required fields are marked *