com.threewks.thundr.mail.JavaMailMailer.java Source code

Java tutorial

Introduction

Here is the source code for com.threewks.thundr.mail.JavaMailMailer.java

Source

/*
 * This file is a component of thundr, a software library from 3wks.
 * Read more: http://3wks.github.io/thundr/
 * Copyright (C) 2014 3wks, <thundr@3wks.com.au>
 *
 * 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.threewks.thundr.mail;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.InternetHeaders;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import org.apache.commons.lang3.StringUtils;

import com.atomicleopard.expressive.Expressive;
import com.threewks.thundr.http.ContentType;
import com.threewks.thundr.http.Header;
import com.threewks.thundr.view.BasicViewRenderer;
import com.threewks.thundr.view.ViewResolverRegistry;

import jodd.util.Base64;

/**
 * An implementation of {@link Mailer} which uses javax.mail.
 */
public class JavaMailMailer extends BaseMailer {

    public JavaMailMailer(ViewResolverRegistry viewResolverRegistry) {
        super(viewResolverRegistry);
    }

    @Override
    protected void sendInternal(Map.Entry<String, String> from, Map.Entry<String, String> replyTo,
            Map<String, String> to, Map<String, String> cc, Map<String, String> bcc, String subject, Object body,
            List<Attachment> attachments) {
        try {
            Session emailSession = getSession();

            Message message = new MimeMessage(emailSession);
            message.setFrom(emailAddress(from));
            if (replyTo != null) {
                message.setReplyTo(new Address[] { emailAddress(replyTo) });
            }

            message.setSubject(subject);

            BasicViewRenderer viewRenderer = render(body);
            String content = viewRenderer.getOutputAsString();
            String contentType = ContentType.cleanContentType(viewRenderer.getContentType());
            contentType = StringUtils.isBlank(contentType) ? ContentType.TextHtml.value() : contentType;

            if (Expressive.isEmpty(attachments)) {
                message.setContent(content, contentType);
            } else {
                Multipart multipart = new MimeMultipart("mixed"); // subtype must be "mixed" or inline & regular attachments won't play well together
                addBody(multipart, content, contentType);
                addAttachments(multipart, attachments);
                message.setContent(multipart);
            }

            addRecipients(to, message, RecipientType.TO);
            addRecipients(cc, message, RecipientType.CC);
            addRecipients(bcc, message, RecipientType.BCC);

            sendMessage(message);
        } catch (MessagingException e) {
            throw new MailException(e, "Failed to send an email: %s", e.getMessage());
        }
    }

    protected Session getSession() {
        return Session.getDefaultInstance(new Properties());
    }

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

    private void addBody(Multipart multipart, String content, String contentType) throws MessagingException {
        BodyPart messageBodyPart = new MimeBodyPart();
        messageBodyPart.setContent(content, contentType);
        multipart.addBodyPart(messageBodyPart);
    }

    private void addRecipients(Map<String, String> to, Message message, RecipientType recipientType)
            throws MessagingException {
        if (Expressive.isNotEmpty(to)) {
            List<Address> addresses = new ArrayList<>();
            for (Entry<String, String> recipient : to.entrySet()) {
                addresses.add(emailAddress(recipient));
            }
            message.addRecipients(recipientType, addresses.toArray(new Address[0]));
        }
    }

    private void addAttachments(Multipart multipart, List<Attachment> attachments) throws MessagingException {
        for (Attachment attachment : attachments) {
            BasicViewRenderer response = render(attachment.view());
            byte[] base64Encoded = Base64.encodeToByte(response.getOutputAsBytes());

            InternetHeaders headers = new InternetHeaders();
            headers.addHeader(Header.ContentType, response.getContentType());
            headers.addHeader(Header.ContentTransferEncoding, "base64");

            MimeBodyPart part = new MimeBodyPart(headers, base64Encoded);
            part.setFileName(attachment.name());
            part.setDisposition(attachment.disposition().value());

            if (attachment.isInline()) {
                part.setContentID(attachment.contentId());
            }

            multipart.addBodyPart(part);
        }
    }

    private InternetAddress emailAddress(Map.Entry<String, String> entry) {
        try {
            return StringUtils.isBlank(entry.getValue()) ? new InternetAddress(entry.getKey())
                    : new InternetAddress(entry.getKey(), entry.getValue());
        } catch (Exception e) {
            throw new MailException(e,
                    "Failed to send an email - unable to set a sender or recipient of '%s' <%s>: %s",
                    entry.getKey(), entry.getValue(), e.getMessage());
        }
    }
}