Sending an Email using the JavaMail API

 

Overview

    Purpose

    This tutorial covers sending email from a Java EE application using the JavaMail API.

    Time to Complete

    Approximately 45 minutes.

    Introduction

    The JavaMail API defines classes which represent the components of a mail system. JavaMail does not implement an email server, instead it allows you to access an email server using a Java API. In order to test the code presented in this tutorial you must have access to an email server. While the JavaMail API specification does not mandate support for specific protocols, JavaMail typically includes support for POP3, IMAP, and SMTP. This tutorial covers sending mail messages and only requires access to an SMTP server.

    Scenario

    Sending an email from within a Java application has many practical uses. A web application may allow visitors to create an account. Part of the account creation process could include sending an email with a unique activation code to verify that a valid email address was given at signup. Online shopping applications typically notify buyers of order or tracking status via email.

    Hardware and Software Requirements

    The following is a list of hardware and software requirements:

    • Download and install Java JDK 7 from this link.
    • Download and install an IDE and Application Server such as NetBeans 7.1.2 with Java EE which includes GlassFish 3.1.2 (Java EE download bundle) from this link. During installation, be sure to check the box to install GlassFish. JUnit is an optional installation and not required for this tutorial.
    • Access to an SMTP server
    • Valid credentials (username and password) for the SMTP server
    • The project created in this tutorial can be downloaded from here.

    Prerequisites

    Before starting this tutorial, you should:

    • Have access to an SMTP server. You must know the host name, port number, and security settings for your SMTP server. Web mail providers may offer SMTP access, view your email account settings or help to find further information. Be aware that your username is often your full email address and not just the name that comes before the @ symbol.
    • A Java EE IDE and Application Server such as GlassFish or Oracle WebLogic Server. JavaMail can be downloaded and used as a library in a Java SE application but this tutorial assumes the use of a Java EE application server which would already include JavaMail.
    • Have basic familiarity with Servlets and Session EJBs (helpful but not required)
 

Create a Java EE 6 Web Application

    To create a Java EE 6 Web Application (WAR) project, perform the following steps in the NetBeans IDE:

    Create a new Web Application

    Select File->New Project from the NetBeans menu.

    Select the Java Web category and a project type of Web Application.

    Click Next.

    Enter a project name of EmailSender.

    Click Next.

    Select GlassFish Server 3.1.2 (or other Java EE 6 Full Profile Server) as the server.

    Select Java EE 6 Web as the Java EE Version. This will allow you to create a Session EJB within the web project. Java EE 5 requires a separate project for EJBs.

    Click Finish.

    You should now have a Web Application project with an index.jsp file.

 

Create the required JSP, Servlet, and EJB components

    You will create a JSP containing a form allowing you to specify a email recipient, subject, and message body. The form will submit to a Servlet which will read the form parameters. The Servlet will pass the form parameters to a sendEmail method in Session EJB you will create.

     

    The Session EJB

      Create the com.example.EmailSessionBean class. This class is a local-interface stateless session EJB. You will add the JavaMail functionality to the EmailSessionBean in a later section.

      Right-click on the EmailSender project and select New->Other.

      In the New File window, select a category of Enterprise JavaBeans and a file type of Session Bean.

      Click Next.

      Give the EJB a name of EmailSessionBean.

      The EmailSessionBean should be in the com.example package, have a session type of Stateless and not create any interfaces.

      Click Finish.

      Add a method named sendEmail to EmailSessionBean.

      The sendEmail method should have three parameters of type String named to, subject, and body.

      Save the com.example.EmailSessionBean class.

      You will complete the implementation of the sendEmail method in a later section after you have created all the components of the application.

     

    The Servlet

      Create the com.example.EmailServlet class.

      Right-click on the EmailSender project and select New->Other.

      In the New File window, select a category of Web and a file type of Servlet.

      Click Next.

      Give the Servlet a name of EmailServlet.

      The EmailServlet should be in the com.example package.

      Click Finish.

      Add a field of type EmailSessionBean named emailBean to the EmailServlet.

      The emailBean field should use the @EJB annotation to inject a reference to an EmailSessionBean.

      @EJB
      private EmailSessionBean emailBean;
                                                      

      Within the processRequest method read and save the values of the to, subject, and body form parameters.

      String to = request.getParameter("to");
      String subject = request.getParameter("subject");
      String body = request.getParameter("body");

      Call the emailBean.sendEmail method, passing in the to, subject, and body values as arguments.

      emailBean.sendEmail(to, subject, body);

      While not done in this tutorial, a public production quality application should validation all form parameters. The JavaMail API has the ability to validate the format of an email address. Note that the only way to check the existence of an email address is to attempt to send an email to a given address.

      javax.mail.internet.InternetAddress ia = new javax.mail.internet.InternetAddress(to);
      try {
          ia.validate();
      } catch (javax.mail.internet.AddressException ae) {
      
      }

      Modify the EmailServlet to produce HTML output indicating that the form was submitted.

     

    The JSP

      Open the existing index.jsp file from the Web Pages portion of the EmailSender project.

      You will modify the index.jsp file to produce the output shown in the figure.

      Modify the title and heading of the page to say Email.

      Add a form to the body of the index.jsp page which contains two text inputs named to and subject along with a textarea named body.

      <form method="POST" action="EmailServlet">
          <label for="to">To:</label><input id="to" name="to" type="text"/><br/>
          <label for="subject">Subject:</label><input id="subject" name="subject" type="text"/><br/>
          <textarea name="body" cols="60" rows="15"></textarea><br/>
          <input type="submit" value="Send"/>
      </form>

      You should now be able to deploy and run the EmailSender project. No emails will actually be sent when you submit the form. You will add the email sending capability in the next section.

 

Sending a Plain Text Email with the JavaMail API

    In this section you will send a plain text email using the JavaMail API.

     

    A Protocol Enum

      Create an enumeration to represent your possible protocol choices for sending an email: SMTP, SMTPS, or SMTP with TLS.

      Create the com.example.Protocol enum.

      Right-click on the EmailSender project and select New->Other.

      In the New File window, select a category of Java and a file type of Java Enum.

      Click Next.

      Give the enum a name of Protocol.

      The Protocol enum should be in the com.example package.

      Click Finish.

      Modify the Protocol enum to contain three fields, SMTP, SMTPS, and TLS.

      public enum Protocol {
          SMTP,
          SMTPS,
          TLS
      }

     

    The EmailSessionBean Class

      Open the EmailSessionBean class.

      Add private fields to contain all the information needed to send an email.

      private int port = 465;
      private String host = "smtp.example.com";
      private String from = "matt@example.com";
      private boolean auth = true;
      private String username = "matt@example.com";
      private String password = "secretpw";
      private Protocol protocol = Protocol.SMTPS;
      private boolean debug = true;

      You must modify the value of theses fields to match your SMTP server.

      Create a Properties object to contain settings for the SMTP protocol provider. You can view a list of possible properties and their descriptions from the com.sun.mail.smtp package here.

      Properties props = new Properties();
      props.put("mail.smtp.host", host);
      props.put("mail.smtp.port", port);
      switch (protocol) {
          case SMTPS:
              props.put("mail.smtp.ssl.enable", true);
              break;
          case TLS:
              props.put("mail.smtp.starttls.enable", true);
              break;
      }

      If SMTP authentication is required you must set the mail.smtp.auth property and construct a Authenticator instance that returns a PasswordAuthentication instance with your username and password.

      Authenticator authenticator = null;
      if (auth) {
          props.put("mail.smtp.auth", true);
          authenticator = new Authenticator() {
              private PasswordAuthentication pa = new PasswordAuthentication(username, password);
              @Override
              public PasswordAuthentication getPasswordAuthentication() {
                  return pa;
              }
          };
      }

      Create a Session instance using the Properties object and the Authenticator object. If SMTP authentication in not needed a null value can be supplied for the Authenticator.

      Session session = Session.getInstance(props, authenticator);
      session.setDebug(debug);

      The session.setDebug(boolean) method can be used to print out the current session's activity.

      Construct a MimeMessage instance, populate the message headers and content and then send the message.

      MimeMessage message = new MimeMessage(session);
      try {
          message.setFrom(new InternetAddress(from));
          InternetAddress[] address = {new InternetAddress(to)};
          message.setRecipients(Message.RecipientType.TO, address);
          message.setSubject(subject);
          message.setSentDate(new Date());
          message.setText(body);
          Transport.send(message);
      } catch (MessagingException ex) {
          ex.printStackTrace();
      }

      Run the fix imports wizard (Ctrl+Shift+I) to add any required imports.

      Deploy and run the application

      Write an email to yourself

      After pressing Send an email should be sent to the destination you specified in the form.

      Check your INBOX to verify that the message arrived.

      View the debug output in the GlassFish Server Output tab in NetBeans in the event of an error.

 

Sending an HTML Email with the JavaMail API

    This section will show you how to send an HTML email. You will modify the EmailSessionBean class to send a message consisting of both a HTML body and a plain text alternative. When the recipient of the email can not view the HTML version of the content the plain text version will be show instead.

    Open the EmailSessionBean class.

    Find and comment out the message.setText(body); line.

    Create a MimeMultipart instance with an alternative sub-type. A mulit-part message consists of multiple parts, in this case an HTML and a text message (other possible parts are file attachments). The alternative sub-type indicates that the multiple message parts are alternative versions of the same content.

    Multipart multipart = new MimeMultipart("alternative");

    Create a MimeBodyPart instance to contain the text body part

    MimeBodyPart textPart = new MimeBodyPart();
    String textContent = "Hi, Nice to meet you!";
    textPart.setText(textContent);

    Create a MimeBodyPart instance to contain the HTML body part. Order is important, the preferred format of an alternative multi-part message should be added last.

    MimeBodyPart htmlPart = new MimeBodyPart();
    String htmlContent = "<html><h1>Hi</h1><p>Nice to meet you!</p></html>";
    htmlPart.setContent(htmlContent, "text/html");

    Add both MimeBodyPart instances to the MimeMultipart instance and set the MimeMultipart instance as the MimeMessage.

    multipart.addBodyPart(textPart);
    multipart.addBodyPart(htmlPart);
    message.setContent(multipart);

    Use Transport.send(message); to sent the message (unchanged from the plain text example).

    Run the fix imports wizard (Ctrl+Shift+I) to add any required imports.

    Deploy and run the application. If your email reading application supports HTML email then you should see varying font sizes in the email.

 

Additional Information

    The following relevant information may aid you when developing JavaMail applications.

    Use debugging to troubleshoot JavaMail problems

    The session.setDebug(boolean) method enables debugging output and can help you determine if there is a communication or authorization problem.

    You should turn off debug in a working production environment.

    Verify your user name and password if using SMTP authentication (sending email requires logging in).

    Passwords are usually case sensitive.

    User names are often your full email address (such as matt@example.com) and not just your name.

    Residential Internet Service Providers (ISPs) frequently block SMTP related ports (25 is the most frequently blocked).

    Attempt to configure and use a local email client such as Thunderbird to verify connectivity and settings.

    SMTP servers may limit the amount of outgoing messages.

    If delivery is functioning but suddenly stops, you may have passed an outbound messaging limit. Sometimes if you wait a while (it may be hours) your ability to send messages will be restored.

    For large volumes of outgoing messages you may need to pay for a business class SMTP account or setup your own SMTP server.

    Do not relay spam

    The example in this tutorial would allow anyone to send an email to any destination from the address coded in the application. Posting the example as-is on a public website is inadvisable.

    Web mail accounts may not offer SMTP access.

    Not all web mail providers offer SMTP access. Some providers charge a fee for SMTP access and others require you to enable it.

    Try enabling IMAP or POP3 access if you don't see an option to enable SMTP in your web mail account.

    Self-signed certs require special handling in JavaMail.

    If you have configured your own SMTP server with a self-signed cert special handling will be required. See: http://www.oracle.com/technetwork/java/javamail145sslnotes-1562622.html.

    Secure SMTP (SMTPS vs SMTP with TLS)

    When using SMTPS the network connection is encrypted from the very beginning of the connection.

    SMTP with TLS starts off as an unencrypted SMTP connection and is promoted to a secure connection using TLS.

    SMTPS and TLS are not the same thing. SMTPS typically uses port 465 and TLS uses port 25 or occasionally an alternate port such as 587.

    You must use the mechanism required by your SMTP server. Some SMTP providers offer both mechanisms.

    If your SMTP server requires a user name and a password (SMTP authentication) then it will often also require a secure connection to prevent your user name and password from being sent in an unencrypted form over the internet.

    Send emails asynchronously

    EJB 3.1 (Java EE 6) Session bean methods can be annotated with @Asynchronous. Asynchronous methods return immediately upon invocation.

 

Summary

    In this tutorial, you have learned how to:

    • Send a plain text email using JavaMail
    • Send an HTML email using JavaMail

    Resources

    Credits

    • Lead Curriculum Developer: Matt Heimer