【Java】JavaでEmail ~ SMTP認証 ~

■ はじめに

https://dk521123.hatenablog.com/entry/2016/07/16/222422
https://dk521123.hatenablog.com/entry/2016/07/17/023459

の続き。
今度は、SMTP認証に対応する。

【1】ポイント

* Sessionを作る際に、違いがある

1)SMTP認証なし

Properties props = new Properties();
Session session = Session.getInstance(props, null);

2)SMTP認証あり

Properties props = new Properties();
props.put("mail.smtp.auth", "true");
Authenticator authenticator = new javax.mail.Authenticator() {
  protected PasswordAuthentication getPasswordAuthentication() {
     return new PasswordAuthentication("SMTP_USERNAME", "SMTP_PASSWORD");
  }
};
Session session = Session.getInstance(props, authenticator);

【2】サンプル

package com.sample.mail;

import java.io.UnsupportedEncodingException;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
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.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;

public class EmailHandler {
  private final static String DEFAULT_TIMEOUT = "10000";
  private final static String DEFAULT_HOST = "localhost";
  private final static String DEFAULT_POST = "25";
  private String fromAddress;
  private List<String> toAddresses;
  private List<String> ccAddresses;
  private List<String> bccAddresses;
  private String mailSubject;
  private String mailBody;
  private String atachmentFilePath;
  private String host;
  private String port;
  private String timeout;
  private boolean isEnabledSmtpAuthentication;
  private String smtpUsername;
  private String smtpPassword;
  private boolean isOnDebugMode;

  /**
   * Default Contractor.
   */
  public EmailHandler() {
    this.fromAddress = null;
    this.toAddresses = new ArrayList<>();
    this.ccAddresses = new ArrayList<>();
    this.bccAddresses = new ArrayList<>();
    this.mailSubject = null;
    this.mailBody = null;
    this.atachmentFilePath = null;
    this.host = DEFAULT_HOST;
    this.port = DEFAULT_POST;
    this.timeout = DEFAULT_TIMEOUT;
    this.isEnabledSmtpAuthentication = false;
    this.smtpUsername = null;
    this.smtpPassword = null;
    this.isOnDebugMode = false;
  }

  public void setFromAddress(String fromAddress) {
    this.fromAddress = fromAddress;
  }

  public void setToAddresses(List<String> toAddresses) {
    this.toAddresses = toAddresses;
  }

  public void addToAddress(String toAddress) {
    this.toAddresses.add(toAddress);
  }

  public void setCcAddresses(List<String> ccAddresses) {
    this.ccAddresses = ccAddresses;
  }

  public void addCcAddress(String ccAddress) {
    this.ccAddresses.add(ccAddress);
  }

  public void setBccAddresses(List<String> bccAddresses) {
    this.bccAddresses = bccAddresses;
  }

  public void addBccAddress(String bccAddress) {
    this.bccAddresses.add(bccAddress);
  }

  public void setMailSubject(String mailSubject) {
    this.mailSubject = mailSubject;
  }

  public void setMailBody(String mailBody) {
    this.mailBody = mailBody;
  }

  public void setAtachmentFilePath(String atachmentFilePath) {
    this.atachmentFilePath = atachmentFilePath;
  }

  public void setHost(String host) {
    this.host = host;
  }

  public void setPort(String port) {
    this.port = port;
  }
  
  public void setOnDebugMode(boolean isOnDebugMode) {
    this.isOnDebugMode = isOnDebugMode;
  }

  public void setEnabledSmtpAuthentication(boolean isEnabledSmtpAuthentication) {
    this.isEnabledSmtpAuthentication = isEnabledSmtpAuthentication;
  }

  public void setSmtpUsername(String smtpUsername) {
    this.smtpUsername = smtpUsername;
  }

  public void setSmtpPassword(String smtpPassword) {
    this.smtpPassword = smtpPassword;
  }

  public void send() throws MessagingException, UnsupportedEncodingException {
    if (this.toAddresses == null || this.host == null) {
      throw new InvalidParameterException();
    }

    Properties props = new Properties();
    props.put("mail.smtp.host", this.host);
    props.put("mail.smtp.port", this.port);
    props.put("mail.debug", this.isOnDebugMode);
    props.put("mail.smtp.connectiontimeout", this.timeout);
    props.put("mail.smtp.timeout", this.timeout);

    Session session = this.createSession(props);

    Message mimeMessage = new MimeMessage(session);
    mimeMessage.setFrom(this.toInternetAddress(this.fromAddress));

    InternetAddress[] toAddresses = this.toInternetAddresses(this.toAddresses);
    mimeMessage.setRecipients(Message.RecipientType.TO, toAddresses);

    InternetAddress[] ccAddresses = this.toInternetAddresses(this.ccAddresses);
    mimeMessage.setRecipients(Message.RecipientType.CC, ccAddresses);

    InternetAddress[] bccAddresses = this.toInternetAddresses(this.bccAddresses);
    mimeMessage.setRecipients(Message.RecipientType.BCC, bccAddresses);

    mimeMessage.setSubject(this.mailSubject);
    mimeMessage.setSentDate(new Date());

    BodyPart messageBodyPart = new MimeBodyPart();
    messageBodyPart.setText(this.mailBody);
    messageBodyPart.setContent(this.mailBody, "text/html");
    Multipart multipart = new MimeMultipart();
    multipart.addBodyPart(messageBodyPart);

    // 2つ目は画像を添付する
    if (this.atachmentFilePath != null) {
      MimeBodyPart mimeBodyPart = new MimeBodyPart();
      FileDataSource fileDataSource = new FileDataSource(this.atachmentFilePath);
      DataHandler dataHandler = new DataHandler(fileDataSource);
      mimeBodyPart.setDataHandler(dataHandler);
      mimeBodyPart.setFileName(MimeUtility.encodeWord(dataHandler.getName()));
      multipart.addBodyPart(mimeBodyPart);
    }
    mimeMessage.setContent(multipart);
    Transport.send(mimeMessage);
  }

  private Session createSession(Properties props) {
    if (this.isEnabledSmtpAuthentication) {
      props.put("mail.smtp.auth", "true");
      
      Authenticator authenticator = new javax.mail.Authenticator() {
        protected PasswordAuthentication getPasswordAuthentication() {
          return new PasswordAuthentication(smtpUsername, smtpPassword);
        }
      };
      return Session.getInstance(props, authenticator);
    } else {
      return Session.getInstance(props, null);
    }
  }

  private InternetAddress[] toInternetAddresses(List<String> addresses) throws AddressException {
    InternetAddress[] returnValues = new InternetAddress[addresses.size()];

    int index = 0;
    for (String address : addresses) {
      returnValues[index] = this.toInternetAddress(address);
      index++;
    }

    return returnValues;
  }

  private InternetAddress toInternetAddress(String address) throws AddressException {
    return new InternetAddress(address);
  }

  /**
   * 【使用例】
   * 
   * @param args
   */
  public static void main(String[] args) {
    try {
      EmailHandler email = new EmailHandler();
      email.setPort("587");
      email.setFromAddress("sample@yahoo.com");
      email.addToAddress("to.sample@gmail.com");
      email.addCcAddress("cc.sample@gmail.com");
      email.addBccAddress("bcc.sample@gmail.com");
      email.setMailSubject("test");
      email.setMailBody("body");
      email.setOnDebugMode(true);
      email.setEnabledSmtpAuthentication(true);
      email.setSmtpUsername("smtp_username");
      email.setSmtpPassword("smtp_password");
      email.setAtachmentFilePath("C:\\temp\\Book1.xlsx");
      email.send();
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }
}

参考文献

http://qiita.com/rubytomato@github/items/b106ff8011bcad60bce2
http://piyopiyocs.blog115.fc2.com/blog-entry-215.html

関連記事

JavaでEmail ~ JavaMail / Text ~
https://dk521123.hatenablog.com/entry/2016/07/16/222422
JavaでEmail ~ JavaMail / 添付ファイル ~
https://dk521123.hatenablog.com/entry/2016/07/17/023459
Amazon SES ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2017/04/28/234103