How to use Android JavaMail API to Send Emails

On February 23, 2024
18min read
Veljko Ristić Content Manager @ Mailtrap
This is a graphic representation of JavaMail API via Android devices for the article that covers the topic in detail.

The quick, and let’s say, easy way to send emails from your Android application is to use Intent. However, it can take you only so far due to the method’s limitations. 

This article explores Android JavaMail API as a more flexible and scalable method to send emails.

First, I’ll detail the reasons to opt for JavaMail API instead of Intent, then I’ll jump into the implementation tutorials with code examples. 

When and why should you send emails without Android Intent?

Simply, it’s all about having more flexibility, reliability, and control in various applications and scenarios. But here’s a more granular overview of why to consider JavaMail integration to send an email from an Android app. 

  • Server-side control: Using server-side technologies (like SMTP) to send emails gives you more control over the email-sending process. This method is more reliable for automated emails, such as notifications or system-generated messages, where you need confirmation that the email was sent successfully.
  • Customization and formatting: Compared to what you can get natively from Android Studio and ‘intent.action_send’, server-side email sending allows for more complex HTML formatting and customization. Proper sending solutions like Mailtrap Email Sending can offer more robust formatting options.
  • Avoiding user interaction: Under specific circumstances, you may want to send emails in the background without user intervention or without a dialog box to notify the user. However, Android Intent requires the user to manually complete the email-sending process in an email client. In contrast, server-side sending can happen automatically without user interference.
  • Bulk or scheduled emails: This isn’t feasible with Android Intent, but server-side solutions can handle bulk emailing and scheduling.
  • Security and privacy: Simply, server-side solutions can provide better security measures (e.g. encryption). It helps avoid exposing sensitive content or docs to third-party email clients on the user’s device.
  • Avoiding email client dependency: You’d want to ensure the email functionality is not dependent on the presence of an email client on the user’s device. Some users might not have a default email client set up, which is a requirement for Android Intent-based email sending.
  • Compliance and logging: Server-side emailing can offer detailed logs and comply with specific regulations, which is crucial for certain types of applications, especially in business or healthcare sectors.

Keynotes before we continue:

  • This tutorial doesn’t tell you how to import Android dependencies within the studio. If you need to set New Intent in the XML file, check this article. It covers the Intent method in full. 
  • Ideally, you should test the flows on an Android device, be it an Android phone or tablet. If you use emulators you need to make sure that the Email app has been set up. Better yet, you’d also configure Gmail (Gmail app) and Microsoft Outlook to have a clear preview over different clients. 
  • This tutorial covers only email, not the SMS sending functionality. 
  • Pro tip – don’t use Gmail SMTP to send emails from Android. There are quite stringent throughput limitations and may require additional programming. 

Android send email through JavaMail

JavaMail API provides a platform and protocol-independent framework to build mail and messaging applications. 

To no surprise, JavaMail API requires careful handling of background operations to ensure top-level security. I’ll guide you through setup and implementation and I’ll be dedicating special attention to the security measures.  

Note: There’s also an option to set up Android email sending using Kotlin, but this tutorial exclusively uses Java. 

Setup

  1. Step – Adding dependencies 

Add the following dependencies to the build.gradle file. 

implementation 'com.sun.mail:jakarta.mail:2.0.1'
implementation 'com.sun.activation:jakarta.activation:2.0.1'
  1. Step – Adding internet permission

JavaMail requires internet access so you need to add the associated permission to AndroidManifest.xml.

<uses-permission android:name="android.permission.INTERNET"/>

Implementation

The sections further down the article cover detailed implementation (SMTP and API). But here’s a quick overview so you understand the scope.  

  1. Email session configuration: You need to create a method to configure the email session. For example, this involves setting properties like the mail protocol (SMTP), host, port, and authentication details. 
  1. Composing the message: Use MimeMessage to compose an email. Within that header, you’ll be setting the sender’s email, recipient’s email, subject, and email body. 
  1. Sending the message: Finally, you establish the connection with the email server using the Transport.send() command, and then send the message. 

Also, you’ll need to choose a proper sending service like Mailtrap Email Delivery Platform, which will be featured in this article. 

Important Note:

Email sending via JavaMail API should be an asynchronous operation within a background thread. When sending emails from a background thread, you avoid blocking the UI thread. 

Send email in Android with JavaMail and external SMTP

In this quick tutorial, I assume you’ve added the necessary dependencies and the internet permission. The tutorial is also geared towards Mailtrap users. 

Step 1 – Configure Mailtrap SMTP

You can find the SMTP credentials under the “SMTP Settings” section. Within Mailtrap, this is the second step of the Sending Domains setup process. 

Mailtrap Email Sending - Sending Domains menu

Keep in mind that you need to verify and authenticate your domain to be able to send emails. During the verification process, you’ll be asked to add DNS records to your domain provider’s DNS. 

Learn more about DNS records and their importance in our Email deliverability cheatsheet playlist ⬇️. 

That out of the way, here are the exemplary credentials 

  • Host: live.smtp.mailtrap.io* 
  • Port: 587 (recommended)
  • Username: api**
  • Password: Mailtrap password specific to your account

Notes:

  • *live.smtp.mailtrap.io is the endpoint for sending transactional emails. If you want to send bulk (marketing) emails, the endpoint is bulk.smtp.mailtrap.io. But first, make sure to accept the terms of service to unlock the Bulk Stream. 
  • **api is the universal username for all Mailtrap Email Sending users. 

Step 2 – Create an email sender class 

import jakarta.mail.Authenticator
import jakarta.mail.BodyPart
import jakarta.mail.Message
import jakarta.mail.MessagingException
import jakarta.mail.Session
import jakarta.mail.Transport
import jakarta.mail.internet.InternetAddress
import jakarta.mail.internet.MimeBodyPart
import jakarta.mail.internet.MimeMessage
import jakarta.mail.internet.MimeMultipart

val props = System.getProperties()
props["mail.smtp.host"] = ‘sandbox.smtp.mailtrap.io’
                props["mail.smtp.socketFactory.port"] = ‘587’
                props["mail.smtp.socketFactory.class"] = "javax.net.ssl.SSLSocketFactory"
                props["mail.smtp.auth"] = true
                props["mail.smtp.port"] = ‘587’
                props["mail.smtp.starttls.enable"] = true
val session = Session.getInstance(props,
                    object : Authenticator() {
                        //Authenticating the password
                        override fun getPasswordAuthentication(): jakarta.mail.PasswordAuthentication {
                            return jakarta.mail.PasswordAuthentication(smtpUsername, smtpPassword)
                        }
                    })
 // Create a default MimeMessage object.
                    val message = MimeMessage(session)

                    // Set From: header field of the header.
                    message.setFrom(InternetAddress(‘from@example.com’))
                    toRecipients?.forEach { email ->
                        message.addRecipients(
                            Message.RecipientType.TO,
                            InternetAddress.parse(email.trim())
                        )
                    }

                    // Set Subject: header field
                    message.subject = subject

                    // Send message
                    Transport.send(message)

Step 3 – Implement the asynchronous email sending

As I mentioned earlier, you should avoid network operations on the main thread and use AsyncTask or a similar action. Here’s the example for the AsyncTask

new AsyncTask<Void, Void, Void>() {
    @Override
    protected Void doInBackground(Void... voids) {
        new MailtrapEmailSender().sendEmail("your_mailtrap_username", "your_mailtrap_password", "to@example.com", "Subject", "Email Body");
        return null;
    }
}.execute();

Step 4 – Error handling and security

When creating the email sender class, you can use a catch block for scenarios like no internet connection, incorrect credentials, etc.

If a MessagingException is caught, the code inside the catch block executes. It throws a new RuntimeException, effectively converting a checked exception (MessagingException) into an unchecked one (RuntimeException). 

Optionally, you can make the handling more granular to improve debugging and user experience. Here’s an example:

catch (MessagingException e) {
    // Log the exception for debugging purposes
    Log.e("MailtrapEmailSender", "Email sending failed", e);

    // More user-friendly error handling
    // For example, you might notify the user through a UI element
    // or send error details to a remote server for analysis
}

As for security, the Authenticator class is used to obtain the credentials.

When the session needs to authenticate to the SMTP server (as specified by mail.smtp.auth property being true), it calls this getPasswordAuthentication() method to obtain the credentials.

It’s a safer way to handle credentials that way, as it allows for dynamic retrieval of credentials.

Now, this particular implementation doesn’t retrieve credentials from a secure server, but it can be modified to do it. 

You only need to replace the return statement inside the getPasswordAuthentication() command with the code to securely fetch credentials from a server or other secure storage. 

For example, I’ll assume you have a secure server endpoint that provides email credentials in response to an authentication request. The modified code is as follows. 

import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;

public class SecureMailAuthenticator extends Authenticator {

    private String credentialEndpoint;

    public SecureMailAuthenticator(String credentialEndpoint) {
        this.credentialEndpoint = credentialEndpoint;
    }

    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        try {
            URL url = new URL(credentialEndpoint);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            // Add any necessary headers or authentication details to the request

            Scanner scanner = new Scanner(connection.getInputStream());
            if (scanner.hasNext()) {
                String credentials = scanner.nextLine();
                // Assuming credentials are returned in format "username:password"
                String[] parts = credentials.split(":");
                return new PasswordAuthentication(parts[0], parts[1]);
            }
        } catch (Exception e) {
            // Handle exceptions (e.g., network errors, parsing errors)
        }
        return null;
    }
}

In this code:

SecureMailAuthenticator class is a custom Authenticator class that extends javax.mail.Authenticator.

The constructor takes a URL (credentialEndpoint) pointing to the server endpoint that provides the credentials.

getPasswordAuthentication override does several things consecutively:

  • Opens a connection to the specified URL.
  • Sends a GET request (you might need to add headers or other authentication mechanisms depending on your server setup).
  • Reads the response (assumed to be in the format “username:password”).
  • Splits the response to extract the username and password.
  • Returns a new PasswordAuthentication object with the obtained credentials.

Lastly, if you choose this method, make sure the server endpoint is indeed secure and uses HTTPS. Also, don’t forget to implement proper authentication and authorization on the server itself to safeguard the credentials. 

How to send an HTML email with attachments to multiple recipients

I’ll be tweaking the code to send emails with attachments to multiple recipients via an external SMTP. There’ll be a few changes to the code and I’ll provide explanations right under the example. 

import java.util.Properties;
import javax.mail.*;
import javax.mail.internet.*;

public class MailtrapEmailSender {

    public static void main(String[] args) {
        // Mailtrap SMTP configuration
        String host = "live.smtp.mailtrap.io";
        String port = "587";
        String username = "your_mailtrap_username";
        String password = "your_mailtrap_password";

        // Email properties
        Properties prop = new Properties();
        prop.put("mail.smtp.auth", "true");
        prop.put("mail.smtp.starttls.enable", "true");
        prop.put("mail.smtp.host", host);
        prop.put("mail.smtp.port", port);
        prop.put("mail.smtp.ssl.trust", host);

        // Authenticating with Mailtrap
        Session session = Session.getInstance(prop, new Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, password);
            }
        });

        try {
            // Compose the message
            MimeMessage message = new MimeMessage(session);
            message.setFrom(new InternetAddress("from@example.com"));
            message.setRecipients(Message.RecipientType.TO,
                    InternetAddress.parse("recipient1@example.com,recipient2@example.com")); // Multiple recipients
            message.setSubject("Test Email with HTML and Attachments");

            // Create multipart object for email content
            Multipart emailContent = new MimeMultipart();

            // HTML Text
            MimeBodyPart htmlPart = new MimeBodyPart();
            htmlPart.setContent("<h1>This is an HTML Email!</h1>", "text/html");
            emailContent.addBodyPart(htmlPart);

            // Attachment
            MimeBodyPart attachmentPart = new MimeBodyPart();
            attachmentPart.attachFile("/path/to/file"); // Specify the file path
            emailContent.addBodyPart(attachmentPart);

            // Set content
            message.setContent(emailContent);

            // Send the email
            Transport.send(message);

            System.out.println("Email sent successfully");

        } catch (MessagingException | IOException e) {
            e.printStackTrace();
        }
    }
}

In this code:

  • Again, I created a Session object using Mailtrap SMTP settings. 
  • To compose the email, I created a MimeMessage object and set the sender, recipients (multiple), email subject, and body (HTML content).
  • I used MimeMultipart to structure the email with different parts, such as the main body and the attachments. 
  • The HTML content is added as one part of the email. If necessary, you can also send text/plain email. 
  • For attachments, I created a new part for each file and added it to the email. Yes, the example can handle multiple attachments. 

Lastly, the error handling and security are basic here since we already covered a few different options in the previous section. But if you’re curious about increased security for the attachments, check the “Send with attachments” section under email API. 

Send email in Android with JavaMail and email API

Using an email API provides a direct way to send emails from your Android app without needing an SMTP server setup. As always, you need to ensure to handle the API token securely and manage network responses and errors effectively.

I’ll be using Mailtrap Email API and it’s necessary to add additional dependencies so you can make an HTTP request. 

Remember: You need to verify and authenticate your sending domain with Mailtrap to send via API or SMTP. 

Step 1 – Adding dependencies and the internet permission 

I’ll add the OkHttp dependency to the build.gradle file. 

implementation 'com.squareup.okhttp3:okhttp:4.9.1'

Internet permission in the AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>

Step 2 – Get Mailtrap API token

You can get your Mailtrap API token under Settings, the API Tokens menu.

Mailtrap Email Sending API Tokens menu

Make sure you have Domain or Account Admin permission for the domain you’ll use to send emails. If not, contact your Account Admin or Owner to grant you the permission. 

Then, you can click the More menu (three vertical dots) and hit Copy token to copy it to your clipboard. 

Step 3 – Create an email sender class 

Like with SMTP, I’ll create an email sender class, only this time it’s designed for API calls. 

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;

public class MailtrapApiEmailSender {

    private final String mailtrapApiToken;
    private final OkHttpClient client = new OkHttpClient();

    public MailtrapApiEmailSender(String mailtrapApiToken) {
        this.mailtrapApiToken = mailtrapApiToken;
    }

    public void sendEmail(String recipient, String subject, String body) throws IOException {
       OkHttpClient client = new OkHttpClient();
                    String json = "{\n" +
                            "  \"to\": [\n" +
                            "    {\n" +
                            "      \"email\": \"" + recipient + "\",\n" +
                            "      \"name\": \"Recipient Name\"\n" +
                            "    }\n" +
                            "  ],\n" +
                            "  \"from\": {\n" +
                            "    \"email\": \"anyname@freelance.mailtrap.link\",\n" +
                            "    \"name\": \"Sender Name\"\n" +
                            "  },\n" +
                            "  \"subject\": \"" + subject + "\",\n" +
                            "  \"text\": \"" + body + "\"\n" +
                            "}";
                    MediaType mediaType = MediaType.parse("application/json");
                    RequestBody requestBody = RequestBody.create(json, mediaType);
                    Request request = new Request.Builder()
                            .url("https://send.api.mailtrap.io/api/send")
                            .addHeader("Content-Type", "application/json")
                            .addHeader("Accept", "application/json")
                            .addHeader("Api-Token", token)
                            .post(requestBody)
                            .build();

                    client.newCall(request).enqueue(new Callback() {
                        @Override
                        public void onResponse(@NonNull okhttp3.Call call, @NonNull Response response) {
                            sbSendEmail.dismiss();
                            if (response.isSuccessful()) {
                                Snackbar.make(binding.getRoot(), "Email Sent!", Snackbar.LENGTH_LONG).show();
                            } else {
                                Snackbar.make(binding.getRoot(), "Something Went Wrong!", Snackbar.LENGTH_LONG).show();
                            }
                        }

                        @Override
                        public void onFailure(@NonNull okhttp3.Call call, @NonNull IOException e) {
                            e.printStackTrace();
                            Snackbar.make(binding.getRoot(), "Something Went Wrong!", Snackbar.LENGTH_LONG).show();
                        }
                    });
    }
}

Step 4 – Implement asynchronous email sending

Again, you want to avoid operations on the main thread, and I’ll be using the AsyncTask

new AsyncTask<Void, Void, Void>() {
    @Override
    protected Void doInBackground(Void... voids) {
        try {
            new MailtrapApiEmailSender("your_mailtrap_api_token").sendEmail("to@example.com", "Subject", "Email Body");
        } catch (IOException e) {
            e.printStackTrace(); // Handle exceptions appropriately
        }
        return null;
    }
}.execute();

Step 5 – Error handling and security

In the example above, the error handling is managed through the try-catch block. The current implementation throws a generic IOException for any unsuccessful response. 

A more robust approach would be to analyze the response further and throw different exceptions based on the exact issue (e.g., authentication failure, rate limiting, invalid request format). Here’s an example of the extended error handling:

       try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                handleErrorResponse(response);
            }
            // Handle successful response or return it
        }
    }

    private void handleErrorResponse(Response response) throws EmailSendingException, IOException {
        switch (response.code()) {
            case 401:
                throw new EmailSendingException("Authentication failed.");
            case 429:
                throw new EmailSendingException("Rate limit exceeded.");
            case 400:
                throw new EmailSendingException("Invalid request format.");
            default:
                throw new IOException("Unexpected code " + response);
        }
    }

    // Custom exception for email sending errors
    public static class EmailSendingException extends Exception {
        public EmailSendingException(String message) {
            super(message);
        }
    }
}

As always, you should avoid exposing your API token in the code. 

In the example under Step 3, the API token is passed to the MailtrapApiEmailSender constructor, meaning it’s not hardcoded within the class. This is a good practice as it allows the token to be stored and retrieved securely from outside the class, such as from encrypted storage or a secure server.

The code uses HTTPS (https://send.api.mailtrap.io/api/send) for sending requests, which is critical for ensuring the data transmitted is encrypted and secure from eavesdropping or man-in-the-middle attacks. 

Yeah, there’s still room for improvement. I won’t go into code examples here, but just list the points you may consider implementing, particularly if you wish to send at a volume. 

  • Token exposure: Although the token isn’t hardcoded, it’s still passed around, which could expose it to risks if not handled carefully. Ideally, the token should be accessed in a way that minimizes its exposure in memory and logs.
  • Error logging: While not directly a security issue, careful error logging (without exposing sensitive information like tokens) can help identify and address security-related issues more quickly.
  • Input validation: Before creating the JSON request, validating inputs like recipient, subject, and body can prevent injection attacks or unintended errors.

Send HTML email

I’ll continue with the example used for the API method and adjust the MailtrapApiEmailSender class. Here’s the updated implementation:

import okhttp3.*;

import java.io.IOException;

public class MailtrapApiEmailSender {

    private final String mailtrapApiToken;
    private final OkHttpClient client = new OkHttpClient();

    public MailtrapApiEmailSender(String mailtrapApiToken) {
        this.mailtrapApiToken = mailtrapApiToken;
    }

    public void sendEmail(String recipient, String subject, String htmlBody) throws IOException, EmailSendingException {
        // Construct JSON payload with HTML content
        String json = "{\"to\": \"" + recipient + "\", \"subject\": \"" + subject + "\", \"html_body\": \"" + htmlBody + "\"}";
        RequestBody requestBody = RequestBody.create(json, MediaType.get("application/json; charset=utf-8"));

        Request request = new Request.Builder()
            .url("https://send.api.mailtrap.io/api/send")
            .addHeader("Authorization", "Bearer " + mailtrapApiToken)
            .post(requestBody)
            .build();

        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                handleErrorResponse(response);
            }
            // Handle or log the successful response
        }
    }

    private void handleErrorResponse(Response response) throws EmailSendingException, IOException {
        switch (response.code()) {
            case 401:
                throw new EmailSendingException("Authentication failed.");
            case 429:
                throw new EmailSendingException("Rate limit exceeded.");
            case 400:
                throw new EmailSendingException("Invalid request format.");
            default:
                throw new IOException("Unexpected code " + response);
        }
    }

    public static class EmailSendingException extends Exception {
        public EmailSendingException(String message) {
            super(message);
        }
    }
}

In this code:

  • HTML email content: The method sendEmail now accepts htmlBody as a parameter, which should contain your HTML-formatted email content.
  • JSON payload: The JSON payload sent to the Mailtrap API includes the html_body field, ensuring the email body is treated as HTML.
  • Error handling: The method handleErrorResponse interprets different HTTP response codes to throw specific exceptions, offering more detailed insights into potential issues.
  • Custom exception: EmailSendingException is used to indicate issues specific to the email-sending process.

Send email with attachments

Again, I’m extending the example above and its MailtrapApiEmailSender class. Simply put, I’m modifing the way the request body gets created. And since Mailtrap Email API expects the attachments to be sent as part of a multipart request, I’ll adjust the code accordingly. 

import okhttp3.*;

import java.io.File;
import java.io.IOException;
import java.util.List;

public class MailtrapApiEmailSender {

    private final String mailtrapApiToken;
    private final OkHttpClient client = new OkHttpClient();

    public MailtrapApiEmailSender(String mailtrapApiToken) {
        this.mailtrapApiToken = mailtrapApiToken;
    }

    public void sendEmailWithAttachments(String recipient, String subject, String htmlBody, List<String> attachmentPaths) throws IOException, EmailSendingException {
        // Building the multipart request
        MultipartBody.Builder builder = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("to", recipient)
                .addFormDataPart("subject", subject)
                .addFormDataPart("html_body", htmlBody);

        // Adding attachments
        for (String filePath : attachmentPaths) {
            File file = new File(filePath);
            builder.addFormDataPart("attachment", file.getName(),
                    RequestBody.create(file, MediaType.parse("application/octet-stream")));
        }

        RequestBody requestBody = builder.build();

        Request request = new Request.Builder()
            .url("https://send.api.mailtrap.io/api/send")
            .addHeader("Content-Type", "application/json")
            .addHeader("Accept", "application/json")
            .addHeader("Api-Token", mailtrapApiToken)

            .post(requestBody)
            .build();

        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                handleErrorResponse(response);
            }
            // Handle or log the successful response
        }
    }

    private void handleErrorResponse(Response response) throws EmailSendingException, IOException {
        // Error handling logic as before
    }

    // Custom exception class as before

In this code:

  • Multipart request: The MultipartBody.Builder is used to create a multipart request. This is necessary because attachments are binary data and need to be sent differently compared to regular text fields.
  • Adding fields and attachments: The to, subject, and html_body are added as form data parts. Each attachment is added as a separate form data part with its content type specified as "application/octet-stream". This is a generic binary stream type, suitable for file attachments.
  • File handling: For each attachment, a File object is created from the provided path. The file’s name and body are included in the request.
  • Executing the request: The request is sent using the OkHttpClient, and the response is processed similarly to the previous example.

Security measures

Mailtrap API communication happens over HTTPS, ensuring that the data transmitted between the client and the server is encrypted. This includes the HTML content of the email and any attachments. 

As a secure channel, HTTPS safeguards against eavesdropping and tampering. Even so, there are some additional methodologies you might consider. 

  • Encryption of attachments: Individually encrypting attachments before sending could be an additional layer of security to implement. This goes double for sensitive files which may contain personal user data.
  • Checksums and file validation: Checksums for file validation and file type checks would be useful for ensuring file integrity and safety.
  • Antivirus scanning: Antivirus scanning is typically handled at the server or endpoint level.
  • Digital signatures: The digital signatures in the code could be used to verify the authenticity of the sender.

To sum up, HTTPS is a significant step in ensuring secure communication. And the implementation of additional security measures, like encryption of attachments or checksum validation, would depend on the specific requirements and the level of security desired.

Also, note that the more advanced security implementations require modifications to the email-sending mechanisms and the processing logic at the receiving end. 

Send to multiple recipients

Guess what, I’ll be extending the previous example to handle multiple recipients. 😀

The trick is in modifying the sendEmail method to accept a list of recipients instead of a single recipient. I’ll also provide comments to explain the method and the logic behind the code.

import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.File;
import java.io.IOException;
import java.util.List;

public class MailtrapApiEmailSender {

    private final String mailtrapApiToken;
    private final OkHttpClient client = new OkHttpClient();

    public MailtrapApiEmailSender(String mailtrapApiToken) {
        this.mailtrapApiToken = mailtrapApiToken;
    }

    // Method to send an email with attachments to multiple recipients
    public void sendEmail(List<String> recipients, String subject, String body, List<File> attachments) throws IOException {
        // Build the JSON string for the recipients
        StringBuilder recipientJson = new StringBuilder();
        for (String recipient : recipients) {
            if (recipientJson.length() > 0) recipientJson.append(", ");
            recipientJson.append("\"").append(recipient).append("\"");
        }

        // Create the JSON body for the email
        String jsonBody = "{\"to\": [" + recipientJson + "], \"subject\": \"" + subject + "\", \"html_body\": \"" + body + "\"}";
        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        builder.addFormDataPart("data", jsonBody);

        // Add attachments to the request
        for (File attachment : attachments) {
            builder.addFormDataPart("attachment", attachment.getName(), RequestBody.create(attachment, MediaType.get("application/octet-stream")));
        }

        RequestBody requestBody = builder.build();

        // Build and execute the request
        Request request = new Request.Builder()
                .url("https://send.api.mailtrap.io/api/send")
                .addHeader("Authorization", "Bearer " + mailtrapApiToken)
                .post(requestBody)
                .build();

        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
            // Handle response or return it
        }
    }
}

In this code:

  • Multiple recipients handling: The method sendEmail is modified to accept a list of email addresses (List<String> recipients). A JSON array is constructed from this list to include multiple recipients in the API request.
  • Building JSON body: The JSON string for the email body is created with multiple recipients, subject, and HTML body.
  • Attachments handling: The method now accepts a list of File objects as attachments. Each attachment is added as a form data part to the request body.
  • Creating multipart request: We use MultipartBody.Builder to construct a multipart request that includes both the JSON body and the attachments.
  • Executing the request: The request is then built and executed using OkHttpClient, with error handling to catch any issues during the execution.

Test emails before sending: why and how?

Testing emails in a sandbox environment, like the one Mailtrap provides, saves you a lot of trouble in the long run. Here’s a list of key reasons to test emails. 

  1. Catch errors early: The sandbox environment allows you to identify and rectify issues like formatting errors, broken links, or typos before they reach your audience.
Mailtrap Email Testing HTML Source
  1. Verify logic and flow: This is critical for automated or transactional emails. You want to ensure that the right email goes out at the right time. For instance, welcome emails, password resets, or purchase confirmations need to trigger correctly. Or you risk high churn and a bunch of user complaints. 
  1. Content rendering: Emails may display differently across various email clients and devices. Testing helps ensure consistent rendering and a good user experience.
Mailtrap Email Testing HTML
  1. Spam and deliverability checks: A sandbox environment can mimic real-world conditions, helping you assess if your email might be flagged as spam, thus affecting deliverability.
Mailtrap Email Testing Spam Analysis
  1. Privacy and compliance: In a sandbox, you can test with dummy data, ensuring you’re not accidentally sending test emails to real customers, which could be a privacy concern or even a legal issue in some cases.

How to test emails using Mailtrap Email Testing SMTP method

If you haven’t set up Mailtrap Email Testing, now’s the time to do it. With it, you’ll be able to leverage Mailtrap’s ‘fake’ SMTP and inspect and debug emails within a testing Inbox. 

There’s not much to testing configuration (on Android or any other platform). You just need to tweak the code to the Testing SMTP server settings (including server name, port, username, and password). 

You can find the credentials under the SMTP Settings tab of the Inboxes menu. For security, the credentials are hidden, and there’s a list of ready-made Integrations including Play-Mailer for Java. 

Mailtrap Email Testing My Inbox SMTP settings

Then, you just need to send a test email and it’ll appear under your testing inbox almost instantly. Here’s an exemplary code:

package com.example.smtp;

import jakarta.mail.*;
import jakarta.mail.internet.*;
import java.util.Properties;

public class TestMailSender {
    public static void main(String[] args) {

        // Recipient and sender email addresses
        String[] toAddresses = {"demo1@example.com", "demo2@example.com"}; // Multiple recipients
        String from = "sender@example.com";

        // Mailtrap credentials for authentication
        final String username = "your_testing_username";
        final String password = "your_testing_password";
        String host = "sandbox.smtp.mailtrap.io";

        // Setting up mail server properties
        Properties properties = new Properties();
        properties.put("mail.smtp.auth", "true");
        properties.put("mail.smtp.starttls.enable", "true");
        properties.put("mail.smtp.host", host);
        properties.put("mail.smtp.port", "2525");

        // Establishing a mail session with authentication details
        Session session = Session.getInstance(properties, new Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, password);
            }
        });

        try {
            // Crafting the email message
            Message message = new MimeMessage(session);
            message.setFrom(new InternetAddress(from));
           
            // Set multiple recipients
            InternetAddress[] addressTo = new InternetAddress[toAddresses.length];
            for (int i = 0; i < toAddresses.length; i++) {
                addressTo[i] = new InternetAddress(toAddresses[i]);
            }
            message.setRecipients(Message.RecipientType.TO, addressTo);

            message.setSubject("JavaMail with HTML and Attachments");

            // Create a multipart message for attachment
            Multipart multipart = new MimeMultipart();

            // HTML Message part
            BodyPart messageBodyPart = new MimeBodyPart();
            String htmlMessage = "<h1>Hello</h1><p>This is a test email from JavaMail with <b>HTML content</b> and attachments.</p>";
            messageBodyPart.setContent(htmlMessage, "text/html");
            multipart.addBodyPart(messageBodyPart);

            // Attachment part
            messageBodyPart = new MimeBodyPart();
            String filename = "/path/to/file.txt"; // Specify the file to be attached
            DataSource source = new FileDataSource(filename);
            messageBodyPart.setDataHandler(new DataHandler(source));
            messageBodyPart.setFileName(filename);
            multipart.addBodyPart(messageBodyPart);

            // Send the complete message parts
            message.setContent(multipart);

            // Sending the email
            Transport.send(message);
            System.out.println("Email sent successfully with HTML content and attachments to multiple recipients....");
        } catch (MessagingException e) {
            // Handle any exceptions that arise during sending
            throw new RuntimeException(e);
        }
    }
}

The above is like an enhanced testing template to cover all use cases I discussed earlier. It’s an HTML email that can handle attachments and manage multiple recipients. 

How to test emails using Mailtrap Email Testing API method

The key benefit of using the API testing method over SMTP is that it allows you to automate the entire testing process. 

The code below uses OkHttp client to construct an HTTP POST request and “send” an email to a particular testing inbox. In keeping with most of the examples in this article, the request includes the following:

  • Multiple recipients (To, CC, BCC)
  • Sender details
  • Attachments
  • Custom variables
  • Headers
  • Subject
  • Body text 
import okhttp3.*;

public class MailtrapApiEmailSender {
    public static void main(String[] args) throws Exception {
        // Initialize OkHttpClient
        OkHttpClient client = new OkHttpClient();

        // JSON Payload for the API Request
        String jsonPayload = "{\n" +
            "  \"to\": [{\n" +
            "    \"email\": \"john_doe@example.com\",\n" +
            "    \"name\": \"John Doe\"\n" +
            "  }],\n" +
            "  \"cc\": [{\n" +
            "    \"email\": \"jane_doe@example.com\",\n" +
            "    \"name\": \"Jane Doe\"\n" +
            "  }],\n" +
            "  \"bcc\": [{\n" +
            "    \"email\": \"james_doe@example.com\",\n" +
            "    \"name\": \"Jim Doe\"\n" +
            "  }],\n" +
            "  \"from\": {\n" +
            "    \"email\": \"sales@example.com\",\n" +
            "    \"name\": \"Example Sales Team\"\n" +
            "  },\n" +
            // Including an HTML file as an attachment (base64 encoded)
            "  \"attachments\": [{\n" +
            "    \"content\": \"PCFET0NUWVB...\",\n" + // Truncated base64 content
            "    \"filename\": \"index.html\",\n" +
            "    \"type\": \"text/html\",\n" +
            "    \"disposition\": \"attachment\"\n" +
            "  }],\n" +
            "  \"custom_variables\": {\n" +
            "    \"user_id\": \"45982\",\n" +
            "    \"batch_id\": \"PSJ-12\"\n" +
            "  },\n" +
            "  \"headers\": {\n" +
            "    \"X-Message-Source\": \"dev.mydomain.com\"\n" +
            "  },\n" +
            "  \"subject\": \"Your Example Order Confirmation\",\n" +
            "  \"text\": \"Congratulations on your order no. 1234\",\n" +
            "  \"category\": \"API Test\"\n" +
            "}";

        // Building the Request
        Request request = new Request.Builder()
            .url("https://sandbox.api.mailtrap.io/api/send/YOUR_INBOX_ID") // Replace with your Inbox ID
            .post(RequestBody.create(MediaType.parse("application/json"), jsonPayload))
            .addHeader("Content-Type", "application/json")
            .addHeader("Accept", "application/json")
            .addHeader("Api-Token", "YOUR_API_TOKEN") // Replace with your API token
            .build();

        // Executing the request and obtaining the response
        try (Response response = client.newCall(request).execute()) {
            System.out.println("Response Code: " + response.code());
            System.out.println("Response Body: " + response.body().string());
        }
    }
}

In this code:

  • OkHttpClient: Send and receive HTTP requests.
  • JSON Payload: The data to be sent in the API request. It includes recipient information, sender information, email content, and attachments. The attachment is included as a base64 encoded string.
  • Request building: A POST request is built using the Mailtrap API URL. Replace "YOUR_INBOX_ID" and "YOUR_API_TOKEN" with your actual Mailtrap inbox ID and API token.
  • Executing request: The client.newCall(request).execute() sends the request to the Mailtrap API.
  • Response handling: The response from the API is printed to the console, showing the status code and response body.
  • Inbox ID: Your inbox ID is in the URL of that particular inbox, see image below ⬇️. 
Mailtrap Email Testing Inbox ID

Further reading:

Or watching:

The Bot sends emails

From crafting HTML emails with attachments to managing multiple recipients, I don’t think I left any stone unturned. So, the intricacies of Android JavaMail API methodologies, shouldn’t be a taboo for you anymore. 

And of course, you know well which email sending platform gives you optimal testing and sending flexibility. (it’s Mailtrap, just to remind you). 

 

 

Article by Veljko Ristić Content Manager @ Mailtrap

Linguist by trade, digital marketer at heart, I’m a Content Manager who’s been in the online space for 10+ years. From ads to e-books, I’ve covered it all as a writer, editor, project manager, and everything in between. Now, my passion is with email infrastructure with a strong focus on technical content and the cutting-edge in programming logic and flows. But I still like spreading my gospels while blogging purely about marketing.