29

I have a textfield on my app, and a button. I only want that when user press the button, my app have to send a email with the text "Hello" to the direction on the textfield.

Is there a easy way to do it?

Cœur
  • 37,241
  • 25
  • 195
  • 267
NullPointerException
  • 36,107
  • 79
  • 222
  • 382

6 Answers6

55

First way. If you don't want to be linked to the native email program or gmail program (via intent) to send the mail, but have the email sent in the background, see the code below.

Firstly you need to import the following library in Gradle File:

implementation 'javax.mail:mail:1.4.7'

Then you can use this helper class and adjust it to your needs.

package com.myapp.android.model.service;

import android.util.Log;
import com.myapp.android.MyApp;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;

public class MailService {
    // public static final String MAIL_SERVER = "localhost";

    private String toList;
    private String ccList;
    private String bccList;
    private String subject;
    final private static String SMTP_SERVER = DataService
            .getSetting(DataService.SETTING_SMTP_SERVER);
    private String from;
    private String txtBody;
    private String htmlBody;
    private String replyToList;
    private ArrayList<Attachment> attachments;
    private boolean authenticationRequired = false;

    public MailService(String from, String toList, String subject, String txtBody, String htmlBody,
            Attachment attachment) {
        this.txtBody = txtBody;
        this.htmlBody = htmlBody;
        this.subject = subject;
        this.from = from;
        this.toList = toList;
        this.ccList = null;
        this.bccList = null;
        this.replyToList = null;
        this.authenticationRequired = true;

        this.attachments = new ArrayList<Attachment>();
        if (attachment != null) {
            this.attachments.add(attachment);
        }
    }

    public MailService(String from, String toList, String subject, String txtBody, String htmlBody,
            ArrayList<Attachment> attachments) {
        this.txtBody = txtBody;
        this.htmlBody = htmlBody;
        this.subject = subject;
        this.from = from;
        this.toList = toList;
        this.ccList = null;
        this.bccList = null;
        this.replyToList = null;
        this.authenticationRequired = true;
        this.attachments = attachments == null ? new ArrayList<Attachment>()
                : attachments;
    }

    public void sendAuthenticated() throws AddressException, MessagingException {
        authenticationRequired = true;
        send();
    }

    /**
     * Send an e-mail
     *
     * @throws MessagingException
     * @throws AddressException
     */
    public void send() throws AddressException, MessagingException {
        Properties props = new Properties();

        // set the host smtp address
        props.put("mail.smtp.host", SMTP_SERVER);
        props.put("mail.user", from);

        props.put("mail.smtp.starttls.enable", "true");  // needed for gmail
        props.put("mail.smtp.auth", "true"); // needed for gmail
        props.put("mail.smtp.port", "587");  // gmail smtp port

        /*Authenticator auth = new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication("mobile@mydomain.example", "mypassword");
            }
        };*/

        Session session;

        if (authenticationRequired) {
            Authenticator auth = new SMTPAuthenticator();
            props.put("mail.smtp.auth", "true");
            session = Session.getDefaultInstance(props, auth);
        } else {
            session = Session.getDefaultInstance(props, null);
        }

        // get the default session
        session.setDebug(true);

        // create message
        Message msg = new javax.mail.internet.MimeMessage(session);

        // set from and to address
        try {
            msg.setFrom(new InternetAddress(from, from));
            msg.setReplyTo(new InternetAddress[]{new InternetAddress(from,from)});
        } catch (Exception e) {
            msg.setFrom(new InternetAddress(from));
            msg.setReplyTo(new InternetAddress[]{new InternetAddress(from)});
        }

        // set send date
        msg.setSentDate(Calendar.getInstance().getTime());

        // parse the recipients TO address
        java.util.StringTokenizer st = new java.util.StringTokenizer(toList, ",");
        int numberOfRecipients = st.countTokens();

        javax.mail.internet.InternetAddress[] addressTo = new javax.mail.internet.InternetAddress[numberOfRecipients];

        int i = 0;
        while (st.hasMoreTokens()) {
            addressTo[i++] = new javax.mail.internet.InternetAddress(st
                    .nextToken());
        }
        msg.setRecipients(javax.mail.Message.RecipientType.TO, addressTo);

        // parse the replyTo addresses
        if (replyToList != null && !"".equals(replyToList)) {
            st = new java.util.StringTokenizer(replyToList, ",");
            int numberOfReplyTos = st.countTokens();
            javax.mail.internet.InternetAddress[] addressReplyTo = new javax.mail.internet.InternetAddress[numberOfReplyTos];
            i = 0;
            while (st.hasMoreTokens()) {
                addressReplyTo[i++] = new javax.mail.internet.InternetAddress(
                        st.nextToken());
            }
            msg.setReplyTo(addressReplyTo);
        }

        // parse the recipients CC address
        if (ccList != null && !"".equals(ccList)) {
            st = new java.util.StringTokenizer(ccList, ",");
            int numberOfCCRecipients = st.countTokens();

            javax.mail.internet.InternetAddress[] addressCC = new javax.mail.internet.InternetAddress[numberOfCCRecipients];

            i = 0;
            while (st.hasMoreTokens()) {
                addressCC[i++] = new javax.mail.internet.InternetAddress(st
                        .nextToken());
            }

            msg.setRecipients(javax.mail.Message.RecipientType.CC, addressCC);
        }

        // parse the recipients BCC address
        if (bccList != null && !"".equals(bccList)) {
            st = new java.util.StringTokenizer(bccList, ",");
            int numberOfBCCRecipients = st.countTokens();

            javax.mail.internet.InternetAddress[] addressBCC = new javax.mail.internet.InternetAddress[numberOfBCCRecipients];

            i = 0;
            while (st.hasMoreTokens()) {
                addressBCC[i++] = new javax.mail.internet.InternetAddress(st
                        .nextToken());
            }

            msg.setRecipients(javax.mail.Message.RecipientType.BCC, addressBCC);
        }

        // set header
        msg.addHeader("X-Mailer", "MyAppMailer");
        msg.addHeader("Precedence", "bulk");
        // setting the subject and content type
        msg.setSubject(subject);

        Multipart mp = new MimeMultipart("related");

        // set body message
        MimeBodyPart bodyMsg = new MimeBodyPart();
        bodyMsg.setText(txtBody, "iso-8859-1");
        if (attachments.size()>0) htmlBody = htmlBody.replaceAll("#filename#",attachments.get(0).getFilename());
        if (htmlBody.indexOf("#header#")>=0) htmlBody = htmlBody.replaceAll("#header#",attachments.get(1).getFilename());
        if (htmlBody.indexOf("#footer#")>=0) htmlBody = htmlBody.replaceAll("#footer#",attachments.get(2).getFilename());

        bodyMsg.setContent(htmlBody, "text/html");
        mp.addBodyPart(bodyMsg);

        // set attachements if any
        if (attachments != null && attachments.size() > 0) {
            for (i = 0; i < attachments.size(); i++) {
                Attachment a = attachments.get(i);
                BodyPart att = new MimeBodyPart();
                att.setDataHandler(new DataHandler(a.getDataSource()));
                att.setFileName( a.getFilename() );
                att.setHeader("Content-ID", "<" + a.getFilename() + ">");
                mp.addBodyPart(att);
            }
        }
        msg.setContent(mp);

        // send it
        try {
            javax.mail.Transport.send(msg);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * SimpleAuthenticator is used to do simple authentication when the SMTP
     * server requires it.
     */
    private static class SMTPAuthenticator extends javax.mail.Authenticator {

        @Override
        protected PasswordAuthentication getPasswordAuthentication() {

            String username = DataService
                    .getSetting(DataService.SETTING_SMTP_USER);
            String password = DataService
                    .getSetting(DataService.SETTING_SMTP_PASSWORD);

            return new PasswordAuthentication(username, password);
        }
    }

    public String getToList() {
        return toList;
    }

    public void setToList(String toList) {
        this.toList = toList;
    }

    public String getCcList() {
        return ccList;
    }

    public void setCcList(String ccList) {
        this.ccList = ccList;
    }

    public String getBccList() {
        return bccList;
    }

    public void setBccList(String bccList) {
        this.bccList = bccList;
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public void setFrom(String from) {
        this.from = from;
    }

    public void setTxtBody(String body) {
        this.txtBody = body;
    }

    public void setHtmlBody(String body) {
        this.htmlBody = body;
    }

    public String getReplyToList() {
        return replyToList;
    }

    public void setReplyToList(String replyToList) {
        this.replyToList = replyToList;
    }

    public boolean isAuthenticationRequired() {
        return authenticationRequired;
    }

    public void setAuthenticationRequired(boolean authenticationRequired) {
        this.authenticationRequired = authenticationRequired;
    }

}

And use this class:

MailService mailer = new MailService("from@mydomain.example","to@domain.example","Subject","TextBody", "<b>HtmlBody</b>", (Attachment) null);
try {
    mailer.sendAuthenticated();
} catch (Exception e) {
    Log.e(AskTingTing.APP, "Failed sending email.", e);
}

Second way. Another option, if you don't mind using the native email client or gmail on Android for sending the mail (but the user actually has to hit the send button finally in the email client), you can do this:

startActivity(new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:to@gmail.com")));
General Grievance
  • 4,555
  • 31
  • 31
  • 45
Mathias Conradt
  • 28,420
  • 21
  • 138
  • 192
  • 1
    I got a lot of errors on the imports... this is not compatible with android 1.5 and 1.6? – NullPointerException Dec 03 '10 at 11:42
  • you need to add the activation.jar/mail.jar of javax mail to your lib folder of Android. Should also work on 1.6. – Mathias Conradt Dec 03 '10 at 12:15
  • 2
    You need to add the activation.jar/mail.jar of javax mail to your lib folder (create it if it doesn't exist yet, in your project root folder). You can download the jars from the web, i.e. http://www.oracle.com/technetwork/java/index-138643.html – Mathias Conradt Dec 03 '10 at 14:39
  • I downloaded javamail-1.4.3.zip but it haves A LOT OF FILES, a bunch of multiple format files, and a lot of jars on it... wich one i have to add to my project? – NullPointerException Dec 03 '10 at 15:30
  • i tryed adding mail.jar, but i still have problems with this import: import javax.activation.DataHandler; – NullPointerException Dec 03 '10 at 15:36
  • sorry, can you please read what I am writing more carefully. I have mentioned before, you put mail.jar and activation.jar in the lib. – Mathias Conradt Dec 03 '10 at 15:36
  • but activation.jar doesn't exist's on that zip file :S – NullPointerException Dec 03 '10 at 15:44
  • ok i find activation.jar 1.0.2 on internet, i add it and now imports doesn't give me fails, but now i have errors on the code, "cannot be resolved" errors... : DataService cannot be resolved, Attachment cannot be resolved to a type – NullPointerException Dec 03 '10 at 15:49
  • these two classes are just helper classes from my project, you can replace the constants with your own values. If you don't send attachments, you can comment those lines out. For the line with DataService, just put your smtp server as string directly. – Mathias Conradt Dec 03 '10 at 16:13
  • My SMTP server? i dont have a smtp server, i just wanna send a simple mail. Im reading what is a SMTP server on google and it's too hard to make one :S what should i do? – NullPointerException Dec 03 '10 at 16:18
  • if you send an email, you're always using an smtp server. if you have gmail, you also use their smtp server. (smtp.gmail.com), etc. If you don't mind using the native email client for sending the mail, you can use a different approach, maybe simpler. Will add the code in a minute. – Mathias Conradt Dec 03 '10 at 16:28
  • but with that new line of code i can set the body and the subject of the mail. I have to send a predefined subject and body, just in java, not dinamic, how i can do it? – NullPointerException Dec 03 '10 at 16:39
  • it seems not to work... i tryed sending some emails and i still didn't recive none of them – NullPointerException Dec 03 '10 at 16:54
  • is the DataService Class a Class that is defined by you or is a part of the jars? I am trying to test the code out above but I am getting the error that it cannot be found – JenniferG Jan 24 '16 at 01:54
  • @JenniferG It's my own and simply just returns some configuration strings. You can remove the DataService calls and just use simple strings for smtp username and password. – Mathias Conradt Jan 24 '16 at 19:53
  • how can i get smtp username and password? Isn't this free? –  Nov 09 '16 at 07:52
  • @14bce109 I don't get the question. You can use Gmail for free, yes, (just register an account on their website) but you would still need a username/password then in order to authenticate. – Mathias Conradt Nov 10 '16 at 07:50
  • Long story short: No, you can't just add a magic .jar lib and send emails as many as you want. You still need an SMTP server, either from Gmail or set up your own. Period. – Kirill Karmazin Mar 30 '19 at 14:39
  • @MathiasConradt what is DataService class here ? is that an inbuilt class or custom class?? – krishnamurthy Apr 22 '19 at 11:09
  • @krishnamurthy That's just a custom helper class that reads properties from a property file, you could as well hardcode the settings without it. – Mathias Conradt Apr 25 '19 at 16:15
  • @MathiasConradt DataService.SETTING_SMTP_USER , DataService.SETTING_SMTP_PASSWORD means receiver's emailID and password ?? can you please share me the DataService class ? krishnamca089@gmail.com thank you . – krishnamurthy Apr 30 '19 at 09:38
  • My post is 9 years old, I don't have that class or project anymore available, and if so, I would just contains three constants with values that aren't of much use to you. No, SMTP settings has nothing to do with the receiver, it's the outgoing (SMTP) mail server config / authentication. – Mathias Conradt Apr 30 '19 at 13:14
16

Add This line of code in your submit button

 final Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
                              emailIntent.setType("text/plain");
                              emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String\[\]{  "serveroverloadofficial@gmail.com"});
                              emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Hello There");
                              emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, "Add Message here");


                                emailIntent.setType("message/rfc822");

                            try {
                                startActivity(Intent.createChooser(emailIntent,
                                        "Send email using..."));
                            } catch (android.content.ActivityNotFoundException ex) {
                                Toast.makeText(getActivity(),
                                        "No email clients installed.",
                                        Toast.LENGTH_SHORT).show();
                            }

                        }
                    });

Android will automatically choose clients avilable in your device and user will be free to choose any Email client he want

Intent app chooser

Suppose user choose gmail as mailing client it would look like this:-

Send mail simply

Plus point for this method is you are not adding any extra jar in App & givinguser freedom to choose action.

Hitesh Sahu
  • 41,955
  • 17
  • 205
  • 154
6

Took the code from this thread and tidied it up into Kotlin.

I also only wanted to do simple email sending, not all the other features (like attachments). 2020 TLS is always on, so did some tidy up there as well. Only 1 Gradle dependency needed also.

I also found this list of email POP services really helpful:

https://support.office.com/en-gb/article/pop-and-imap-email-settings-for-outlook-8361e398-8af4-4e97-b147-6c6c4ac95353

How to use:

    val auth = EmailService.UserPassAuthenticator("yourUser", "yourPass")
    val to = listOf(InternetAddress("to@example.com"))
    val from = InternetAddress("from@example.com")
    val email = EmailService.Email(auth, to, from, "Test Subject", "Hello Body World")
    val emailService = EmailService("yourSmtpServer", 587)

    GlobalScope.launch {
        emailService.send(email)
    }

The code:

import java.util.*
import javax.mail.*
import javax.mail.internet.InternetAddress
import javax.mail.internet.MimeBodyPart
import javax.mail.internet.MimeMessage
import javax.mail.internet.MimeMultipart

class EmailService(private var server: String, private var port: Int) {

    data class Email(
        val auth: Authenticator,
        val toList: List<InternetAddress>,
        val from: Address,
        val subject: String,
        val body: String
    )

    class UserPassAuthenticator(private val username: String, private val password: String) : Authenticator() {
        override fun getPasswordAuthentication(): PasswordAuthentication {
            return PasswordAuthentication(username, password)
        }
    }

    fun send(email: Email) {
        val props = Properties()
        props["mail.smtp.auth"] = "true"
        props["mail.user"] = email.from
        props["mail.smtp.host"] = server
        props["mail.smtp.port"] = port
        props["mail.smtp.starttls.enable"] = "true"
        props["mail.smtp.ssl.trust"] = server
        props["mail.mime.charset"] = "UTF-8"
        val msg: Message = MimeMessage(Session.getDefaultInstance(props, email.auth))
        msg.setFrom(email.from)
        msg.sentDate = Calendar.getInstance().time
        msg.setRecipients(Message.RecipientType.TO, email.toList.toTypedArray())
//      msg.setRecipients(Message.RecipientType.CC, email.ccList.toTypedArray())
//      msg.setRecipients(Message.RecipientType.BCC, email.bccList.toTypedArray())
        msg.replyTo = arrayOf(email.from)

        msg.addHeader("X-Mailer", CLIENT_NAME)
        msg.addHeader("Precedence", "bulk")
        msg.subject = email.subject

        msg.setContent(MimeMultipart().apply {
            addBodyPart(MimeBodyPart().apply {
                setText(email.body, "iso-8859-1")
                //setContent(email.htmlBody, "text/html; charset=UTF-8")
            })
        })
        Transport.send(msg)
    }

    companion object {
        const val CLIENT_NAME = "Android StackOverflow programmatic email"
    }
}

Gradle:

dependencies {
    implementation 'com.sun.mail:android-mail:1.6.4'
}
Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Blundell
  • 75,855
  • 30
  • 208
  • 233
3
        public class MainActivity extends Activity 
        {
            private static final String username = "emailaddress";
            private static final String password = "password";
            private EditText emailEdit;
            private EditText subjectEdit;
            private EditText messageEdit;
            private Multipart _multipart;

            @SuppressLint("SdCardPath")
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);

                emailEdit = (EditText) findViewById(R.id.email);
                subjectEdit = (EditText) findViewById(R.id.subject);
                messageEdit = (EditText) findViewById(R.id.message);
                Button sendButton = (Button) findViewById(R.id.send);

                sendButton.setOnClickListener(new View.OnClickListener() 
                {
                    @Override
                    public void onClick(View view) 
                    {
                        String email = emailEdit.getText().toString();
                        String subject = subjectEdit.getText().toString();
                        String message = messageEdit.getText().toString();

                        sendMail(email, subject, message);
                    }
                });
            }

            private void sendMail(String email, String subject, String messageBody) 
            {
                Session session = createSessionObject();

                try {
                    Message message = createMessage(email, subject, messageBody, session);
                    new SendMailTask().execute(message);
                } catch (AddressException e) {
                    e.printStackTrace();
                } catch (MessagingException e) {
                    e.printStackTrace();
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }

            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); 
                } 
            private Message createMessage(String email, String subject, String messageBody, Session session) throws MessagingException, UnsupportedEncodingException {
                Message message = new MimeMessage(session);
                message.setFrom(new InternetAddress("tutorials@tiemenschut.com", "Tiemen Schut"));
                message.addRecipient(Message.RecipientType.TO, new InternetAddress(email, email));
                message.setSubject(subject);
                message.setText(messageBody);
                return message;
            }

            private Session createSessionObject() {
                Properties properties = new Properties();
                properties.put("mail.smtp.auth", "true");
                properties.put("mail.smtp.starttls.enable", "true");
                properties.put("mail.smtp.host", "smtp.gmail.com");
                properties.put("mail.smtp.port", "587");

                return Session.getInstance(properties, new javax.mail.Authenticator() {
                    protected PasswordAuthentication getPasswordAuthentication() {
                        return new PasswordAuthentication(username, password);
                    }
                });
            }

            private class SendMailTask extends AsyncTask<Message, Void, Void> {
                private ProgressDialog progressDialog;

                @Override
                protected void onPreExecute() {
                    super.onPreExecute();
                    progressDialog = ProgressDialog.show(MainActivity.this, "Please wait", "Sending mail", true, false);
                }

                @Override
                protected void onPostExecute(Void aVoid) {
                    super.onPostExecute(aVoid);
                    progressDialog.dismiss();
                }

                @Override
                protected Void doInBackground(Message... messages) {
                    try {
                        Transport.send(messages[0]);
                    } catch (MessagingException e) {
                        e.printStackTrace();
                    }
                    return null;
                }
            }
        }

add three jar files in your libs folder and try this Mail.jar!

activation.jar!

additional.jar!

Write the subject or body text directly and remove edittext and you will send directly email from your app.

And don't forget to give INTERNET PERMISSION In your manifest

Dharmesh
  • 53
  • 6
2

Improved Mathias Conradt code

    import android.os.AsyncTask;
    import android.os.Handler;
    import android.os.Looper;
    import androidx.annotation.NonNull;
    import androidx.annotation.Nullable;

    import javax.activation.DataHandler;
    import javax.activation.DataSource;
    import javax.mail.*;
    import javax.mail.internet.*;
    import java.util.*;

    /**
     * @author Ako Tulu & Mathias Conradt
     */
    public class EmailService
    {
        public final static String CLIENT_NAME = "Android Jakarta Mail";

        private String host = null;
        private Integer port = null;
        private boolean startTls = false;
        private boolean enableSelfSigned = true;
        private javax.mail.Authenticator auth = null;
        private InternetAddress from = null;
        private InternetAddress[] toList = null;
        private InternetAddress[] ccList = null;
        private InternetAddress[] bccList = null;
        private Address[] replyToList = null;

        private String subject = null;
        private String txtBody = null;
        private String htmlBody = null;
        private List< Attachment > attachments = new ArrayList<>();

        private PropertyInjector injector = null;

        /**
         * Attachment
         */
        public static class Attachment
        {
            protected final DataSource dataSource;

            public Attachment( final DataSource dataSource )
            {
                this.dataSource = dataSource;
            }

            /**
             * BUG: InputStream has to be new instance every call.
             * Stream is read to retrieve Content-Type and by SMTP write to socket,
             * but stream is read once, reading twice will result in empty result.
             *
             * To retrive Content-Type, library has to copy the stream (be a middleman) or
             * extend itself with a peak command.
             *
             * public InputStream getInputStream()
             */
            DataSource getDataSource()
            {
                return dataSource;
            }
        }

        /**
         * Authenticator
         */
        public static class Authenticator extends javax.mail.Authenticator
        {
            private final String username;
            private final String password;

            public Authenticator( final String username, final String password )
            {
                this.username = username;
                this.password = password;
            }

            @Override
            protected PasswordAuthentication getPasswordAuthentication()
            {
                return new PasswordAuthentication( username, password );
            }
        }

        /**
         * PropertyInjector, if custom properties are needed to be set.
         */
        public interface PropertyInjector
        {
            void inject( Properties properties );
        }

        /**
         * Callback, success if exception is null
         */
        public interface Callback
        {
            void done( @Nullable Exception e );

            static void handle( @Nullable Callback c, Exception e )
            {
                if ( c != null )
                {
                    new Handler( Looper.getMainLooper() ).post( () -> {
                        c.done( e );
                    } );
                }
            }
        }

        /**
         * EmailService
         */
        public EmailService( final String host, final Integer port )
        {
            this.host = host;
            this.port = port;
        }

        /**
         * EmailService
         */
        public EmailService()
        {
        }

        /**
         * Send e-mail, sync or async defined by @async var
         *
         * @throws MessagingException, invalid parameter
         * @throws AddressException,   obsecure string
         */
        public void send( boolean async, @Nullable Callback callback )
        {
            if ( async )
            {
                AsyncTask.execute( () -> {
                    send( callback );
                } );
            }
            else
            {
                send( callback );
            }
        }

        /**
         * Send an e-mail
         *
         * @throws MessagingException, invalid parameter
         * @throws AddressException,   obsecure string
         */
        public void send( @Nullable Callback callback )
        {
            try
            {
                Properties props = new Properties();

                Session session;

                if ( getAuth() != null )
                {
                    props.put( "mail.smtp.auth", "true" );

                    session = Session.getDefaultInstance( props, getAuth() );
                }
                else
                {
                    session = Session.getDefaultInstance( props, null );
                }

                // create message
                Message msg = new javax.mail.internet.MimeMessage( session );

                msg.setFrom( getFrom() );
                msg.setSentDate( Calendar.getInstance().getTime() );
                msg.setRecipients( javax.mail.Message.RecipientType.TO, getToList() );
                msg.setRecipients( javax.mail.Message.RecipientType.CC, getCcList() );
                msg.setRecipients( javax.mail.Message.RecipientType.BCC, getBccList() );
                msg.setReplyTo( getReplyToList() );

                // set header
                msg.addHeader( "X-Mailer", CLIENT_NAME );
                msg.addHeader( "Precedence", "bulk" );

                msg.setSubject( getSubject() );

                // set body message
                Multipart mp = new MimeMultipart();

                MimeBodyPart bodyMsg = new MimeBodyPart();
                bodyMsg.setText( getTxtBody(), "iso-8859-1" );
                bodyMsg.setContent( getHtmlBody(), "text/html; charset=UTF-8" );

                mp.addBodyPart( bodyMsg );

                // set attachments if any
                final List< Attachment > list = getAttachments();
                if ( list.size() > 0 )
                {
                    for ( int i = 0; i < list.size(); i++ )
                    {
                        Attachment a = list.get( i );

                        BodyPart att = new PreencodedMimeBodyPart( "base64" );

                        att.setFileName( a.getDataSource().getName() );
                        att.setDataHandler( new DataHandler( a.getDataSource() ) );

                        mp.addBodyPart( att );
                    }
                }
                msg.setContent( mp );

                if ( getInjector() != null )
                {
                    getInjector().inject( props );
                }
                // set the host smtp address
                props.put( "mail.smtp.host", getHost() );
                props.put( "mail.smtp.port", getPort() );

                props.put( "mail.user", getFrom() );

                if ( isStartTls() )
                {
                    props.put( "mail.smtp.starttls.enable", "true" );
                }

                if ( isEnableSelfSigned() )
                {
                    props.put( "mail.smtp.ssl.trust", getHost() );
                }

                props.put( "mail.mime.charset", "UTF-8" );

                // send it
                javax.mail.Transport.send( msg );

                Callback.handle( callback, null );
            }
            catch ( Exception e )
            {
                Callback.handle( callback, e );
            }
        }

        /**
         * Parse comma separated string into @javax.mail.internet.InternetAddress list
         */
        @NonNull
        public static InternetAddress[] parseAddress( final String address )
                throws AddressException
        {
            List< InternetAddress > list = new ArrayList<>();

            if ( address != null && !"".equals( address ) )
            {
                StringTokenizer st = new StringTokenizer( address, "," );

                while ( st.hasMoreTokens() )
                {
                    list.add( new InternetAddress( st.nextToken() ) );
                }
            }
            return list.toArray( new InternetAddress[ list.size() ] );
        }

        /**
         * Resets internals for reuse
         */
        public EmailService reset()
        {
            this.from = null;
            this.toList = null;
            this.ccList = null;
            this.bccList = null;
            this.replyToList = null;

            this.subject = null;
            this.txtBody = null;
            this.htmlBody = null;
            this.attachments = new ArrayList<>();

            return this;
        }

        public String getHost()
        {
            return host;
        }

        public EmailService setHost( final String host )
        {
            this.host = host;

            return this;
        }

        public Integer getPort()
        {
            return port;
        }

        public EmailService setPort( final String port )
        {
            this.port = Integer.parseInt( port );

            return this;
        }

        public EmailService setPort( final int port )
        {
            this.port = port;

            return this;
        }

        public boolean isEnableSelfSigned()
        {
            return enableSelfSigned;
        }

        public EmailService setEnableSelfSigned( boolean enableSelfSigned )
        {
            this.enableSelfSigned = enableSelfSigned;

            return this;
        }

        public boolean isStartTls()
        {
            return startTls;
        }

        public EmailService setStartTls( boolean startTls )
        {
            this.startTls = startTls;

            return this;
        }

        public javax.mail.Authenticator getAuth()
        {
            return auth;
        }

        public EmailService setAuth( final javax.mail.Authenticator auth )
        {
            this.auth = auth;

            return this;
        }

        public InternetAddress getFrom()
        {
            return from;
        }

        public EmailService setFrom( final String from ) throws AddressException
        {
            this.from = new InternetAddress( from );

            return this;
        }

        public EmailService setFrom( final InternetAddress from )
        {
            this.from = from;

            return this;
        }

        public InternetAddress[] getToList()
        {
            return toList;
        }

        public EmailService setToList( final String toList ) throws AddressException
        {
            return setToList( parseAddress( toList ) );
        }

        public EmailService setToList( final InternetAddress[] toList )
        {
            this.toList = toList;

            return this;
        }

        public InternetAddress[] getCcList()
        {
            return ccList;
        }

        public EmailService setCcList( final String ccList ) throws AddressException
        {
            return setCcList( parseAddress( ccList ) );
        }

        public EmailService setCcList( final InternetAddress[] ccList )
        {
            this.ccList = ccList;

            return this;
        }

        public InternetAddress[] getBccList()
        {
            return bccList;
        }

        public EmailService setBccList( final String bccList ) throws AddressException
        {
            return setBccList( parseAddress( bccList ) );
        }

        public EmailService setBccList( final InternetAddress[] bccList )
        {
            this.bccList = bccList;

            return this;
        }

        public Address[] getReplyToList()
        {
            return replyToList;
        }

        public EmailService setReplyToList( final Address[] replyTo )
        {
            this.replyToList = replyTo;

            return this;
        }

        public String getSubject()
        {
            return subject;
        }

        public EmailService setSubject( final String subject )
        {
            this.subject = subject;

            return this;
        }

        public String getTxtBody()
        {
            return txtBody;
        }

        public EmailService setTxtBody( final String txtBody )
        {
            this.txtBody = txtBody;

            return this;
        }

        public String getHtmlBody()
        {
            return htmlBody;
        }

        public EmailService setHtmlBody( final String htmlBody )
        {
            this.htmlBody = htmlBody;

            return this;
        }

        public List< Attachment > getAttachments()
        {
            return attachments;
        }

        public EmailService setAttachments( final Attachment attachment )
        {
            this.attachments.add( attachment );

            return this;
        }

        public EmailService setAttachments( final List< Attachment > attachments )
        {
            this.attachments = attachments;

            return this;
        }

        public PropertyInjector getInjector()
        {
            return injector;
        }

        public EmailService setInjector( final PropertyInjector injector )
        {
            this.injector = injector;

            return this;
        }

    }

Include dependencies to build.gradle Android project

    dependencies {
        implementation 'com.sun.mail:android-mail:1.6.4'
        implementation 'com.sun.mail:android-activation:1.6.4'
    }

Manifesting a instance of EmailService

    @Override
    public void onCreate( Bundle savedInstanceState )
    {
        super.onCreate( savedInstanceState );

        mEmailService = new EmailService( mConfig.getEmailHost(), mConfig.getEmailPort() )
                .setEnableSelfSigned( mConfig.getEmailSelfSignedCertEnabled() )
                .setStartTls( mConfig.getEmailSTARTTLSEnabled() )
                .setAuth( new EmailService.Authenticator( mConfig.getEmailUsername(), mConfig.getEmailPassword() ) );
    }

Sending E-mail

    try
    {
        final ReservationNotice notice = new ReservationNotice( mConfig.getEmailTemplateBookingReservationNotice() )
                .setHeader( mConfig.getEmailTemplateBookingReservationNoticeHeader() )
                .setFooter( mConfig.getEmailTemplateBookingReservationNoticeFooter() );

        EmailService.Attachment attachment = new EmailService.Attachment( iCalGenerator.create( mBooking, notice, "CalendarEvent.ics" ) );

        mEmailService.reset()
                .setFrom( mBooking.getBookingEmailFromAddress() )
                .setToList( mBooking.getCustomer().getEmail() )
                .setBccList( mBooking.getBookingEmailBCCAddress() )
                .setSubject( mBooking.getEmailTemplateBookingReservationNoticeSubject() )
                .setHtmlBody( notice.buildHTML() )
                .setTxtBody( notice.buildTXT() )
                .setAttachments( attachment );

        mEmailService.send( true, ( e ) -> {
            if ( e != null )
            {
                ErrorDialog.show( e );
                return;
            }
            Toast.makeText( getContext(), R.string.email_sent, Toast.LENGTH_LONG ).show();

        } );
    }
    catch ( MessagingException | IOException e )
    {
        ErrorDialog.show( e );
    }

ReservationNotice is a simple class to build E-mails

    /**
     * @author Ako
     */
    public abstract class BaseEmailBuilder< T extends BaseEmailBuilder >
    {
        protected final String mTemplate;

        protected String mHeader;

        protected String mFooter;

        public T setHeader( final String header )
        {
            mHeader = header;

            return ( T ) this;
        }

        public T setFooter( final String footer )
        {
            mFooter = footer;

            return ( T ) this;
        }

        public BaseEmailBuilder( final String template )
        {
            mTemplate = template;
        }

        public abstract String buildHTML();
        public abstract String buildTXT();
        public abstract String buildICal();

    }

iCalGenerator is a wrapper ontop of iCal4j. Currently only version 2.0 is supported on Android, or Java 1.9+ is needed.

ErrorDialog is a class containing static methods to build AlertDialog.Builder messages.

Ako
  • 956
  • 1
  • 10
  • 13
1

One more thing, I used the approaches given in various answers this site, but it simply wouldn't work. The first problem was the firewall: Transport.send(message) was throwing the following exception:

 javax.mail.MessagingException: Could not connect to SMTP host: smtp.gmail.com, port: 465;
  nested exception is:
    java.net.SocketTimeoutException: failed to connect to smtp.gmail.com/64.233.184.108 (port 465) after 90000ms

If this happens then your firewall is blocking you. Try a different network.

After I've switched network I've received an e-mail from Google that an attempt was made by a less secure application to use my account.

The solution was to enable GMail access for less secure applications. This can be done on this link:

https://support.google.com/accounts/answer/6010255?hl=en

lpapez
  • 49
  • 6