org.codice.alliance.core.email.impl.EmailSenderImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.codice.alliance.core.email.impl.EmailSenderImpl.java

Source

/**
 * Copyright (c) Codice Foundation
 *
 * <p>This is free software: you can redistribute it and/or modify it under the terms of the GNU
 * Lesser General Public License as published by the Free Software Foundation, either version 3 of
 * the License, or any later version.
 *
 * <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details. A copy of the GNU Lesser General Public
 * License is distributed along with this program and can be found at
 * <http://www.gnu.org/licenses/lgpl.html>.
 */
package org.codice.alliance.core.email.impl;

import static org.apache.commons.lang3.Validate.notNull;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
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.xml.ws.Holder;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.codice.alliance.core.email.EmailSender;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <b> This code is experimental. While this interface is functional and tested, it may change or be
 * removed in a future version of the library. </b>
 */
public class EmailSenderImpl implements EmailSender {

    private static final int BUFFER_SIZE = 4096;

    private static final int DEFAULT_PORT = 25;

    private static final long MEGABYTE = 1024L * 1024L;

    private static final long DEFAULT_MAX_ATTACHMENT_SIZE = Long.MAX_VALUE;

    private static final String SMTP_HOST_PROPERTY = "mail.smtp.host";

    private static final Logger LOGGER = LoggerFactory.getLogger(EmailSenderImpl.class);

    private static final String SMTP_PORT_PROPERTY = "mail.smtp.port";

    private static final String SMTP_AUTH_PROPERTY = "mail.smtp.auth";

    private int mailPort = DEFAULT_PORT;

    private String mailHost;

    private long maxAttachmentSize = DEFAULT_MAX_ATTACHMENT_SIZE;

    public void setMailPort(int mailPort) {
        this.mailPort = mailPort;
    }

    public void setMailHost(String mailHost) {
        this.mailHost = mailHost;
    }

    /** @param maxAttachmentSize unit is 1024*1024 bytes */
    public void setMaxAttachmentSize(long maxAttachmentSize) {
        this.maxAttachmentSize = maxAttachmentSize * MEGABYTE;
    }

    /** sendEmail method sends email after receiving input parameters */
    @Override
    public void sendEmail(String fromEmail, String toEmail, String subject, String body,
            List<Pair<String, InputStream>> attachments) throws IOException {
        notNull(fromEmail, "fromEmail must be non-null");
        notNull(toEmail, "toEmail must be non-null");
        notNull(subject, "subject must be non-null");
        notNull(body, "body must be non-null");
        notNull(attachments, "attachments must be non-null");

        if (StringUtils.isBlank(mailHost)) {
            throw new IOException("the mail server hostname has not been configured");
        }

        List<File> tempFiles = new LinkedList<>();

        try {
            InternetAddress emailAddr = new InternetAddress(toEmail);
            emailAddr.validate();

            Properties properties = createSessionProperties();

            Session session = Session.getDefaultInstance(properties);

            MimeMessage mimeMessage = new MimeMessage(session);
            mimeMessage.setFrom(new InternetAddress(fromEmail));
            mimeMessage.addRecipient(Message.RecipientType.TO, emailAddr);
            mimeMessage.setSubject(subject);

            BodyPart messageBodyPart = new MimeBodyPart();
            messageBodyPart.setText(body);

            Multipart multipart = new MimeMultipart();
            multipart.addBodyPart(messageBodyPart);

            Holder<Long> bytesWritten = new Holder<>(0L);

            for (Pair<String, InputStream> attachment : attachments) {

                messageBodyPart = new MimeBodyPart();
                File file = File.createTempFile("email-sender-", ".dat");
                tempFiles.add(file);

                copyDataToTempFile(file, attachment.getValue(), bytesWritten);
                messageBodyPart.setDataHandler(new DataHandler(new FileDataSource(file)));
                messageBodyPart.setFileName(attachment.getKey());
                multipart.addBodyPart(messageBodyPart);
            }

            mimeMessage.setContent(multipart);

            send(mimeMessage);

            LOGGER.debug("Email sent to " + toEmail);

        } catch (AddressException e) {
            throw new IOException("invalid email address: email=" + toEmail, e);
        } catch (MessagingException e) {
            throw new IOException("message error occurred on send", e);
        } finally {
            tempFiles.forEach(file -> {
                if (!file.delete()) {
                    LOGGER.debug("unable to delete tmp file: path={}", file);
                }
            });
        }
    }

    @Override
    public void sendEmail(String fromEmail, String toEmail, String subject, String body) throws IOException {
        sendEmail(fromEmail, toEmail, subject, body, Collections.emptyList());
    }

    private void copyDataToTempFile(File file, InputStream inputStream, Holder<Long> bytesWritten)
            throws IOException {

        try (OutputStream outputStream = new FileOutputStream(file)) {

            byte[] buffer = new byte[BUFFER_SIZE];

            int c;
            while ((c = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, c);
                bytesWritten.value = bytesWritten.value + c;
                if (bytesWritten.value > maxAttachmentSize) {
                    throw new IOException("total attachment size exceeds limit: limit=" + maxAttachmentSize);
                }
            }
        }
    }

    void send(Message message) throws MessagingException {
        Transport.send(message);
    }

    private Properties createSessionProperties() {
        Properties properties = System.getProperties();
        properties.setProperty(SMTP_HOST_PROPERTY, mailHost);
        properties.setProperty(SMTP_AUTH_PROPERTY, "false");
        properties.setProperty(SMTP_PORT_PROPERTY, Integer.toString(mailPort));
        return properties;
    }

    @Override
    public String toString() {
        return "EmailSenderImpl{" + "mailPort=" + mailPort + ", mailHost='" + mailHost + '\''
                + ", maxAttachmentSize=" + maxAttachmentSize + '}';
    }
}