com.haulmont.cuba.core.app.EmailSender.java Source code

Java tutorial

Introduction

Here is the source code for com.haulmont.cuba.core.app.EmailSender.java

Source

/*
 * Copyright (c) 2008-2016 Haulmont.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.haulmont.cuba.core.app;

import com.haulmont.cuba.core.entity.SendingAttachment;
import com.haulmont.cuba.core.entity.SendingMessage;
import com.haulmont.cuba.core.global.EmailHeader;
import com.haulmont.cuba.core.global.FileTypesHelper;
import com.haulmont.cuba.core.global.TimeSource;
import com.haulmont.cuba.core.sys.CubaMailSender;
import org.apache.commons.codec.EncoderException;
import org.apache.commons.codec.net.QCodec;
import org.apache.commons.lang.StringUtils;
import org.perf4j.StopWatch;
import org.perf4j.slf4j.Slf4JStopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Component;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Part;
import javax.mail.internet.*;
import java.io.*;
import java.nio.charset.StandardCharsets;

@Component(EmailSenderAPI.NAME)
public class EmailSender implements EmailSenderAPI {

    private static final Logger log = LoggerFactory.getLogger(EmailSender.class);

    protected JavaMailSender mailSender;

    @Inject
    protected TimeSource timeSource;

    @Resource(name = CubaMailSender.NAME)
    public void setMailSender(JavaMailSender mailSender) {
        this.mailSender = mailSender;
    }

    @Override
    public void sendEmail(SendingMessage sendingMessage) throws MessagingException {
        MimeMessage msg = createMimeMessage(sendingMessage);

        StopWatch sw = new Slf4JStopWatch("EmailSender.send");
        mailSender.send(msg);
        sw.stop();

        log.info("Email '{}' to '{}' has been sent successfully", msg.getSubject(), sendingMessage.getAddress());
    }

    protected MimeMessage createMimeMessage(SendingMessage sendingMessage) throws MessagingException {
        MimeMessage msg = mailSender.createMimeMessage();
        assignRecipient(sendingMessage, msg);
        msg.setSubject(sendingMessage.getCaption(), StandardCharsets.UTF_8.name());
        msg.setSentDate(timeSource.currentTimestamp());

        assignFromAddress(sendingMessage, msg);
        addHeaders(sendingMessage, msg);

        MimeMultipart content = new MimeMultipart("mixed");
        MimeMultipart textPart = new MimeMultipart("related");

        setMimeMessageContent(sendingMessage, content, textPart);

        for (SendingAttachment attachment : sendingMessage.getAttachments()) {
            MimeBodyPart attachmentPart = createAttachmentPart(attachment);

            if (attachment.getContentId() == null) {
                content.addBodyPart(attachmentPart);
            } else
                textPart.addBodyPart(attachmentPart);
        }

        msg.setContent(content);
        msg.saveChanges();
        return msg;
    }

    protected void setMimeMessageContent(SendingMessage sendingMessage, MimeMultipart content,
            MimeMultipart textPart) throws MessagingException {
        MimeBodyPart textBodyPart = new MimeBodyPart();
        MimeBodyPart contentBodyPart = new MimeBodyPart();
        String bodyContentType = getContentBodyType(sendingMessage);

        contentBodyPart.setContent(sendingMessage.getContentText(), bodyContentType);
        textPart.addBodyPart(contentBodyPart);
        textBodyPart.setContent(textPart);
        content.addBodyPart(textBodyPart);
    }

    protected void assignRecipient(SendingMessage sendingMessage, MimeMessage message) throws MessagingException {
        InternetAddress internetAddress = new InternetAddress(sendingMessage.getAddress().trim());
        message.setRecipient(Message.RecipientType.TO, internetAddress);
    }

    protected String getContentBodyType(SendingMessage sendingMessage) {
        String text = sendingMessage.getContentText();
        String bodyContentType;
        if (text.trim().startsWith("<html>")) {
            bodyContentType = "text/html; charset=UTF-8";
        } else {
            bodyContentType = "text/plain; charset=UTF-8";
        }
        return bodyContentType;
    }

    protected void assignFromAddress(SendingMessage sendingMessage, MimeMessage msg) throws MessagingException {
        InternetAddress[] internetAddresses = InternetAddress.parse(sendingMessage.getFrom());
        for (InternetAddress internetAddress : internetAddresses) {
            if (StringUtils.isNotEmpty(internetAddress.getPersonal())) {
                try {
                    internetAddress.setPersonal(internetAddress.getPersonal(), StandardCharsets.UTF_8.name());
                } catch (UnsupportedEncodingException e) {
                    throw new MessagingException("Unsupported encoding type", e);
                }
            }
        }

        if (internetAddresses.length == 1) {
            msg.setFrom(internetAddresses[0]);
        } else {
            msg.addFrom(internetAddresses);
        }
    }

    private void addHeaders(SendingMessage sendingMessage, MimeMessage message) throws MessagingException {
        if (sendingMessage.getHeaders() == null)
            return;
        String[] splitHeaders = sendingMessage.getHeaders().split(SendingMessage.HEADERS_SEPARATOR);
        for (String header : splitHeaders) {
            EmailHeader emailHeader = EmailHeader.parse(header);
            if (emailHeader != null) {
                message.addHeader(emailHeader.getName(), emailHeader.getValue());
            } else {
                log.warn("Can't parse email header: '{}'", header);
            }
        }
    }

    protected MimeBodyPart createAttachmentPart(SendingAttachment attachment) throws MessagingException {
        DataSource source = new MyByteArrayDataSource(attachment.getContent());

        String mimeType = FileTypesHelper.getMIMEType(attachment.getName());
        String encodedFileName = encodeAttachmentName(attachment);

        String contentId = attachment.getContentId();
        if (contentId == null) {
            contentId = encodedFileName;
        }

        String disposition = attachment.getDisposition() != null ? attachment.getDisposition() : Part.INLINE;
        String charset = MimeUtility.mimeCharset(
                attachment.getEncoding() != null ? attachment.getEncoding() : StandardCharsets.UTF_8.name());
        String contentTypeValue = String.format("%s; charset=%s; name=\"%s\"", mimeType, charset, encodedFileName);

        MimeBodyPart attachmentPart = new MimeBodyPart();
        attachmentPart.setDataHandler(new DataHandler(source));
        attachmentPart.setHeader("Content-ID", "<" + contentId + ">");
        attachmentPart.setHeader("Content-Type", contentTypeValue);
        attachmentPart.setFileName(encodedFileName);
        attachmentPart.setDisposition(disposition);

        return attachmentPart;
    }

    protected String encodeAttachmentName(SendingAttachment attachment) {
        String encodedFileName;
        try {
            QCodec qCodec = new QCodec();
            encodedFileName = qCodec.encode(attachment.getName());
        } catch (EncoderException e) {
            encodedFileName = attachment.getName();
        }
        return encodedFileName;
    }

    protected static class MyByteArrayDataSource implements DataSource {
        private byte[] data;

        public MyByteArrayDataSource(byte[] data) {
            this.data = data;
        }

        @Override
        public String getContentType() {
            return "application/octet-stream";
        }

        @Override
        public InputStream getInputStream() throws IOException {
            return new ByteArrayInputStream(data);
        }

        @Override
        public String getName() {
            return "ByteArray";
        }

        @Override
        public OutputStream getOutputStream() throws IOException {
            return null;
        }
    }
}