A Morsel Of Code

One byte at a time

How to send email in PhoneGap (Android) using a gmail account

For the last one month, I have been working on an android app for a grocery store.
I have been using PhoneGap to develop the solution as the client wanted both Android and Iphone version.
I have tried building the app in native Android but going through the hassle of designing css was just too much for me and plus I did not had time to learn Iphone development.

There was a short learning phase for PhoneGap and the results were awesome. However there was one area where I spent hours and ran into several issues. The customer wanted a Feedback section where the user could fill in feedback in a TextArea and hits Submit, which would send an email to customer in the background.

Now PhoneGap has plugin called WebIntent which will open a Email composer where you have to hit Send. This is not what I wanted as customer would have to hit a SUBMIT button, which would open a Email composer window on Phone and then hit Send again. Also this solution also meant user’s email address would be displayed to Grocery store.
I wanted to send the feedback in the background anonymously to Grocery store. I decided to use Java email Api and create a dummy email for grocery store which would be used to send feedback to the Grocery store’s main email address.

I did not find any good tutorial except this one. This is an incomplete tutorial and did not tell you how to create Java classes for Plugin or that you had to make entries in config.xml. So here is the actual tutorial.

Before I begin, let me tell you that I am using latest version of Cordova 2.1.0. This is will not work for Cordova 1.9.0(I will explain the issue below).

Step 1: Add cordova-2.1.0.jar in the project classpath

Step 2: Add cordova-2.1.0.js in the assets/www/js folder.

Step 3: create a new Java class called EmailComoposer.java

package com.dinesh.pb;
import org.apache.cordova.api.Plugin;
import org.apache.cordova.api.PluginResult;
import org.apache.cordova.api.PluginResult.Status;
import org.json.JSONArray;
import org.json.JSONException;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.text.Html;
import com.dinesh.pb.utility.Mail;
 
@SuppressLint("ParserError")
public class EmailComposer extends Plugin {
public final String ACTION_SEND_EMAIL = "sendEmail";

 @Override
 public PluginResult execute(String action, JSONArray arg1, String callbackId) {
 PluginResult result = new PluginResult(Status.INVALID_ACTION);
 if (action.equals(ACTION_SEND_EMAIL)) {
 try {
 String message = arg1.getString(0);
 this.sendEmailViaGmail(message);
 result = new PluginResult(Status.OK);

 }
 catch (JSONException ex) {
 result = new PluginResult(Status.JSON_EXCEPTION, ex.getMessage());
 } catch (Exception e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 } 
 }
 return result;
 }

 private void sendEmailViaGmail(String body) throws Exception{
 Mail m = new Mail("From_email_address@gmail.com", "your password");
 String[] toArr = {"TO_EMAIL_ADDRESS@gmail.com"};
 m.set_to(toArr);
 m.set_from("FROM_EMAIL_ADDRESS@gmail.com");
 m.set_body(body);
 m.set_subject("TEST SUBJECT");
 boolean sendFlag = m.send();

 }

}

Step 4. copy this Mail.java in package of your choice. My package name is com.dinesh.pb.utility.

package com.dinesh.pb.utility;
import java.util.Date;
import java.util.Properties;
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 Mail 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 Mail() { 
 _host = "smtp.gmail.com"; // default smtp server 
 _port = "465"; // default smtp port 
 _sport = "465"; // default socketfactory port 

 _user = ""; // username 
 _pass = ""; // password 
 _from = ""; // email sent from 
 _subject = ""; // email subject 
 _body = ""; // 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); 
 } 

 public Mail(String user, String pass) { 
 this(); 

 _user = user; 
 _pass = pass; 
 } 

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

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

 // send email 
 Transport.send(msg); 

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

 public String[] get_to() {
 return _to;
 }
public void set_to(String[] _to) {
 this._to = _to;
 }
public String get_from() {
 return _from;
 }
public void set_from(String _from) {
 this._from = _from;
 }
public String get_body() {
 return _body;
 }
public void set_body(String _body) {
 this._body = _body;
 }
@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 String get_subject() {
 return _subject;
 }
public void set_subject(String _subject) {
 this._subject = _subject;
 }

 // more of the getters and setters ….. 
 }

Step 5: Update the config.xml and add the details about the new plugin class EmailComposer.java.
Mine looks like this – <plugin name=”EmailComposer” value=”com.dinesh.pb.EmailComposer”/>. Please update the package name value=”com.dinesh.pb.EmailComposer” with your package path.

<?xml version="1.0" encoding="utf-8"?> 
<cordova>
    <access origin="http://127.0.0.1*"/> <!-- allow local pages --> 
    <access origin=".*"/> 
    <log level="DEBUG"/>
    <preference name="useBrowserHistory" value="false" />
    <preference name="exit-on-suspend" value="false" />
<plugins>
    <plugin name="App" value="org.apache.cordova.App"/>
    <plugin name="Geolocation" value="org.apache.cordova.GeoBroker"/>
    <plugin name="Device" value="org.apache.cordova.Device"/>
    <plugin name="Accelerometer" value="org.apache.cordova.AccelListener"/>
    <plugin name="Compass" value="org.apache.cordova.CompassListener"/>
    <plugin name="Media" value="org.apache.cordova.AudioHandler"/>
    <plugin name="Camera" value="org.apache.cordova.CameraLauncher"/>
    <plugin name="Contacts" value="org.apache.cordova.ContactManager"/>
    <plugin name="File" value="org.apache.cordova.FileUtils"/>
    <plugin name="NetworkStatus" value="org.apache.cordova.NetworkManager"/>
    <plugin name="Notification" value="org.apache.cordova.Notification"/>
    <plugin name="Storage" value="org.apache.cordova.Storage"/>
    <plugin name="Temperature" value="org.apache.cordova.TempListener"/>
    <plugin name="FileTransfer" value="org.apache.cordova.FileTransfer"/>
    <plugin name="Capture" value="org.apache.cordova.Capture"/>
    <plugin name="Battery" value="org.apache.cordova.BatteryListener"/>
    <plugin name="SplashScreen" value="org.apache.cordova.SplashScreen"/>
    <plugin name="Echo" value="org.apache.cordova.Echo" />
    <plugin name="EmailComposer" value="com.dinesh.pb.EmailComposer"/>
 </plugins>
</cordova>

Step 6: Create a new javascript file called email.js

var EmailComposer = function(){};
/*
cordova.addConstructor(function() {
    cordova.addPlugin("emailcomposer", new EmailComposer());
});
*/
EmailComposer.prototype.send = function (message){
console.log("Calling the send message");
cordova.exec(function(){ alert('feedback sent')}, 
    function(){ alert('feedback was not sent')}, 
    'EmailComposer', 
    'sendEmail', 
    [message]);
}
function sendFeedback(){
    window.EmailComposer.prototype.send("My message body");
}

Now as I mentioned earlier that I am using cordova-2.1.0.js/jar file there are subtle differences between the latest version and older version (cordova-1.9.0).  If you are using older version you will need to uncomment the section cordova.addConstructorabove and instead of calling

window.EmailComposer.prototype.send("My message body");
Use this:

window.plugins.emailComposer.prototype.send(body);

If you do not use it then you may get error which would say that window.plugins is not defined. If you run into such issues use firebug and see what variables are defined under “window” variable.

Notice the method called “feedback()”. I am simply passing the user text as message body by capturing the input from user feedback TextBox. For simplicity I have just pasted a default Email body.

Step 7: Include the js file in your index.html file

// <!–[CDATA[
javascript" src="js/email.js">
// ]]>

Step 8: Include cordova js file in index.html

// <!–[CDATA[
javascript" src="js/cordova-2.1.0.js">
// ]]>

Step 9: Add three jar files for Java mail api – namely, Activation.jar, Mail.jar and Additional.jar in the libs folder and add it to the classpath. You can these files here.

Cheers!!

UPDATE: A lot of people commented that they could not find mail.jar,additional.jar and actication.jar so I have uploaded them on 4shared.com. You can download them from the link below.

Activation.jar

Additional.jar

Mail.jar

22 comments for “How to send email in PhoneGap (Android) using a gmail account

  1. Alan Hoffmann-Hansen
    July 25, 2013 at 11:16 pm

    I keep getting error :Could not find class ‘test.jjj.com.Mail’, referenced from method email.test.com.EmailComposer.sendEmailViaGmail and Uncaught Error: Error calling method on NPObject. at file:///android_asset/www/cordova??

  2. Animesh Pradhan
    June 17, 2013 at 9:47 am

    How do i set TO , FROM , SUBJECT and BODY from User Input as because I have already set it in the EmailComposer.java .

  3. May 30, 2013 at 8:21 am

    I found a way on how to make this send HTML emails. Anyone looking for a solution of the same problem please follow the guide below:

    You can make this send HTML content by replacing this bit of the ‘send()’ method in Mail.java file:

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

    with

    // setup message body
    BodyPart messageBodyPart = new MimeBodyPart();
    messageBodyPart.setContent(_body, “text/html”);
    _multipart.addBodyPart(messageBodyPart);

  4. May 2, 2013 at 6:31 pm

    This was very very helpful ! I liked the way you explain everything.
    For those who are using this, if you are using the latest version of phonegap – cordova 2.7.0 right now, please make sure you change the EmailComposer.java file to the latest execute method.
    Here is my java file (just in case you cannot figure out) –

    package com.example.phonegap;

    import org.apache.cordova.api.CallbackContext;
    import org.apache.cordova.api.CordovaPlugin;
    import org.json.JSONArray;
    import org.json.JSONException;

    import android.annotation.SuppressLint;

    public class EmailComposer extends CordovaPlugin {
    public final String ACTION_SEND_EMAIL = “sendEmail”;
    // CHECK THIS : http://stackoverflow.com/questions/14972534/plugin-class-is-deprecated-in-phonegap
    @Override
    public boolean execute(String action, JSONArray arg1, CallbackContext callbackContext) {
    //PluginResult result = new PluginResult(Status.INVALID_ACTION);
    if (action.equals(ACTION_SEND_EMAIL)) {
    try {
    String message = arg1.getString(0);
    this.sendEmailViaGmail(message);
    callbackContext.success();
    return true;
    }
    catch (JSONException ex) {
    callbackContext.error(ex.getMessage());
    return false;
    } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    return false;
    }

    private void sendEmailViaGmail(String body) throws Exception{
    Mail m = new Mail(“test@gmail.com”, “password”);
    String[] toArr = {“test@gmail.com”};
    m.set_to(toArr);
    m.set_from(“test@gmail.com”);
    m.set_body(body);
    m.set_subject(“Order”);
    boolean sendFlag = m.send();

    }

    }

    • Karthikeyan Subramani
      May 7, 2013 at 9:25 am

      Is this code working for you.. i am getting following error “The Jar of this class file belongs to container ‘android dependencies’ which does not allow modification to the source attachments in its entries”.

      • May 15, 2013 at 4:30 am

        Yes it is working for me. Please update to latest cordova version. See Nikhil’s code in the comment which shows you how to make changes for latest cordova version.

    • May 15, 2013 at 3:32 am

      Thank you for posting the updated the code. The version of cordova that I used is quite outdated now and your code should help others who are using the latest version.

  5. jyothi
    April 9, 2013 at 9:20 pm

    Hi, I am using cordova2.1.0 and have done every thing you have told . I get “Result of expression’window.EmailComposer’[Undefined] is not an object” … not able to figure out

    • May 3, 2013 at 12:00 am

      Please update the plugin to use newer version. That should solve your problem.

  6. seedorf
    January 23, 2013 at 4:06 pm

    I need someone to walk me through the process step by step because i am getting errors like “Create CommandMap’ in package ‘java.activation’

  7. January 7, 2013 at 2:43 pm

    How do you send the e-mail as html?

  8. Abdulqadir
    December 28, 2012 at 12:29 pm

    Can you please modify this plugin for Cordova-2.2.js latest phonegap version?

  9. tomjm
    November 26, 2012 at 4:42 pm

    I could not find the Additional.jar file but i managed the rest of your instructions and tested it. I keep getting the alert: feedback was not sent. This means that startActivity() is failing. Does any1 know why this could be?

    • tomjm
      November 26, 2012 at 4:45 pm

      Sorry i meant “cordova.exec()” not “startActivity()”

      • tomjm
        November 27, 2012 at 9:05 am

        In the log i am getting: Could not find class ‘javax.activation.DataHandler’, referenced from method com.dinesh.pb.utility.Mail.addAttachment

    • tomjm
      November 27, 2012 at 4:10 pm

      Now i am not getting any errors in the log but the alert keeps coming up: feedback was not sent

      • December 15, 2012 at 5:29 pm

        See my updated post and download the jar file.

  10. amit
    November 20, 2012 at 7:06 am

    how to add “To field” dynamically in “window.EmailComposer.prototype.send(“My message body”);” like if i want “window.EmailComposer.prototype.send(“To”, “My message body”);”

    • November 23, 2012 at 3:26 pm

      You can collect the to field via input param and pass it emailcomposer

  11. October 16, 2012 at 7:04 pm

    How do you create a simple html form for the email to send with this tutorial? I am kinda a noob to javascript still lol.

    • October 19, 2012 at 10:52 pm

      Use dwr to submit the message and send the message to the Java method.

      • shivani
        December 6, 2012 at 5:45 am

        can you please give an example for the same??
        just show an how to incorporate this code in an html file…
        please! its really urgent!

Drop a line or say Hi!