In this use case an Arduio Uno sends HTTP request to PAW which then sends a mail via SMTP to a mail relay.
--------- --------------- | Arduino | ---- HTTP --> | Android / PAW | ---- SMTP --> --------- ---------------So far for the setup seems quite easy.
Unfortunately (as so often) this is not as easy as it seems. The Android API does not include means to send mails via SMTP. Something like JavaMail is not included.
This post will show how to use JavaMail together with PAW to implement the above use case.
You'll find a Short and a Long Version. The Short Version contains only the necessary downloads and scripts to get things running.
For those interested in technical detail there is the Long Version which will explain things in more detail.
There is a pitfall when using Gmail. So in case you are a Gmail user, please read Using Gmail in addition.
Short Version
Download this paw_javamail.zip ZIP file from Google Drive and extract it to your PAW installation folder (normally /sdcard/paw) inside the webconf/dex folder.The ZIP file contains the JavaMail libraries from the javamail-android project together with an utility library to make sending of mails via PAW easier.
After a restart of PAW Server everything should be setup to send mails from the BeanShell console.
Here is a test script:
useDexClasses(); import de.fun2code.paw.mail.*; // Construct a mail class that holds all the server settings mail = new Mail("smtp.gmail.com", 587, "user@gmail.com", "password", Mail.TransportType.TLS); // Send an SMTP message including attachments mail.sendSmtp("sender@gmail.com", "recipient@whatever.com", "Test subject", "Test message ...", new File[] { new File("/sdcard/image1.jpg"), new File("/sdcard/image2.jpg") });
First we create a mail object that holds the SMTP server, authentication and connection settings.
The connection are in this example set to TLS, but could also be SSL or PLAIN.
In this case Gmail ist used but could be any other provider.
The sendSmtp method implements the sending of the mail message and takes sender, recipient, subject, body message and an attachment File array as parameter.
If no attachments should be added, just pass null as parameter.
In case of Gmail you'll have to take additional steps to get this working, please read Using Gmail below.
Using Gmail
When using Gmail, the following Exception is likely to occur:javax.mail.AuthenticationFailedException
The reason for this is that Google does not allow third party apps to access Gmail by default.
In my case I got a mail from Google which included the following link to lower my Gmail security:
https://www.google.com/settings/security/lesssecureapps
After lowering security, everything worked as expected.
Long Version
Let's get a bit into detail ...Why is it necessary to use the files form the javamail-android project and why is a separate utility class needed for sending mails?
My first take on JavaMail was to download the JavaMail JAR file from the official Oracle web site and use it within PAW. For JAR files to work on Android devices they have to be converted into Dalvic Executable (DEXed) format. For more info about DEXing, you can have a look at the following blog post: PAW - Dynamic DEX Class Loading
Not all classes can bed converted into DEX format, some just don't work. That's the case with the Activation classes needed by JavaMail. That's why the official libraries cannot be used.
Here comes the javamail-android project to the rescue which provides DEXable JavaMail libraries.
These are the library included inside the paw_javamail.zip ZIP file.
Inside the ZIP file as well comes a DEXed version of the de.fun2code.paw.mail.Mail class which implements the sending of SMTP messages. Why do we need that class, couldn't we have just put all that code insde a BeanShell script?
In principle yes, but BeanShell on Android does not have the possibility to compile all (inner) classes. That's just not working for the authentication part of JavaMail. So that's why there is this precompiled additional class, which in addition also has the advantage of being faster than the equivalent BeanShell code.
Below is the complete de.fun2code.paw.mail.Mail class which uses plain JavaMail.
package de.fun2code.paw.mail; import java.io.File; import java.util.Properties; import javax.activation.DataHandler; import javax.activation.DataSource; import javax.activation.FileDataSource; import javax.mail.Message; import javax.mail.MessagingException; 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; /** * Class that contains methods to send SMTP messages via JavaMail */ public class Mail { public static enum TransportType { PLAIN, TLS, SSL }; private TransportType transport; private String smtpServer; private int smtpPort; private String username; private String password; /** * The constructor takes the basic connection parameters * * @param smtpServer SMTP server name * @param smtpPort SMTP server name * @param username authentication user name * @param password authentication password * @param transport transport type: PLAIN, TLS or SSL */ public Mail(String smtpServer, int smtpPort, String username, String password, TransportType transport) { this.smtpServer = smtpServer; this.smtpPort = smtpPort; this.username = username; this.password = password; this.transport = transport; } /** * Sends a SMTP mail message * * @param from sender name * @param to recipient name * @param subject mail subject * @param messageText body text * @param attachments attachments to attach * @throws MessagingException */ public void sendSmtp(String from, String to, String subject, String messageText, File[] attachments) throws MessagingException { String strPort = String.valueOf(smtpPort); // Fill basic properties Properties props = new Properties(); props.put("mail.smtp.host", smtpServer); props.put("mail.smtp.auth", "true"); props.put("mail.smtp.port", strPort); // Add connection properties switch(transport) { case TLS: props.put("mail.smtp.starttls.enable", "true"); break; case SSL: System.out.println("Using SSL ..."); props.put("mail.smtp.socketFactory.port", strPort); props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); break; case PLAIN: break; } // Create the session Session session = Session.getInstance(props, new javax.mail.Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username, password); } }); try { // Create MimeMessage Message message = new MimeMessage(session); // Set from header message.setFrom(new InternetAddress(from)); // Set to header message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to)); // Add subject message.setSubject(subject); // Add attachments if available if(attachments != null) { Multipart multipart = new MimeMultipart(); // The body message MimeBodyPart textPart = new MimeBodyPart(); textPart.setText(messageText, "utf-8"); multipart.addBodyPart(textPart); for(File file : attachments) { MimeBodyPart messageBodyPart = new MimeBodyPart(); DataSource source = new FileDataSource(file.getAbsoluteFile()); messageBodyPart.setDataHandler(new DataHandler(source)); messageBodyPart.setFileName(file.getName()); multipart.addBodyPart(messageBodyPart); } message.setContent(multipart); } else { // Add the body message message.setText(messageText); } // Send the message Transport.send(message); } catch(MessagingException e) { throw e; } } }