Powered by Pelican.

p 21 augusztus 2009

Sending email without user interaction in Android

To send emails from an Activity in Android the easiest way is to fire up the built-in mail application with an Intent, and let it take care of the low-level details about how to assemble the message, negotiate a secure connection with the mail server and send it using the proper protocol (as suggested here).  However, there may be cases where this is not applicable, like when the mail should be sent in the background (from a Service, for instance) with no user intervention.  For some users it may not sound like the best idea to just send out mails on their behalf without explicit permission, but there are legitimate use cases where "silent" emailing is necessary.  What SMSForwarder does (automatic forwarding of incoming SMS to a mailbox) is one such case.  If anyone is concerned about privacy -- it is easy to set up an additional email account and use it for archiving SMS.  SMSForwarder does not use the primary Gmail account used by Google apps in Android, the SMTP user and server should be set up directly in the application.

So the question is how to send mails with no user interaction in Android.  Since SMTP is not a difficult protocol, it could be tempting to come up with a bunch of simple SMTP client classes and send outgoing emails directly to the mail server of the recipient (technically speaking, to the MX of the domain the user has an email address in).  However, there are a few catches.  Any reasonable mail server can store emails for temporary network errors, and this is quite difficult to do correctly and efficiently, especially on a mobile device.  MX records also have priorities, and in theory they should be used in increasing priority order when sending emails to a domain.  There are lots of picky SMTP servers out there, so a simplistic approach may not always be adequate.  And, as always, we should not reinvent the wheel.

If one wants to handle SMTP or IMAP in Java the obvious choice of library is javax.mail that was released as open source by Sun some time ago.  This is a great package, with outstanding support for SMTP including ESMTP commands like AUTH and STARTTLS -- these are required by virtually every mail server if anyone wants to use them as a relay (that is, sending mail through them to an external mail server).  It supports MIME too, so one can use it as a full-featured email library -- as a matter of fact, javax.mail is *the* library to do emailing in Java.  The only drawback is its binding to javax.activation, which in turn needs a handful of AWT classes.  Most Android developers are now getting why it is not so straightforward to use javax.mail on Android: since Android implements its own widgets in order to stay away from the somewhat bloated and bulky AWT, either these AWT classes would be needed to be brought to Android, or the dependency on AWT should be eliminated.  Some people claim they have done it, but only a couple of jars can be found with no source code, and most developers are having difficulties even just making them work.

The Jakarta Commons Net project also produces an extensive networking library with SMTP support which basically has no external dependencies like javax.mail.  Unfortunately, it also has its own catch: it only supports basic SMTP commands and semantics, no ESMTP, thus making it a no-go for any serious mail client (good luck relaying a mail via an average mail server without AUTH or STARTTLS).  Nevertheless, this library seemed to be an ideal candidate to extend it with the necessary ESMTP features and make SMSForwarder be able to send mails.

What we did is we implemented the EHLO, AUTH and STARTTLS commands in the commons net library, reusing some code snippets from javax.mail.  The currently supported authentication mechanisms are 'plain' and 'login', but we are also planning to add support for digest-md5 authentication.  The patched library is tested with Gmail and a few other mail servers too.

You can find the patch that can be applied on top of the latest stable Jakarta Commons Net library (version 2.0) here.  For base64 encoding/decoding the Commons Codec library is used.  A conveniently packaged, patched library (with source code) can be downloaded here.

Feel free to comment, give us feedback, or just drop us a line where and how you are using this library.