com.netflix.iep.ses.EmailRequestBuilder.java Source code

Java tutorial

Introduction

Here is the source code for com.netflix.iep.ses.EmailRequestBuilder.java

Source

/*
 * Copyright 2014-2018 Netflix, Inc.
 *
 * 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.netflix.iep.ses;

import com.amazonaws.services.simpleemail.model.Body;
import com.amazonaws.services.simpleemail.model.Destination;
import com.amazonaws.services.simpleemail.model.Message;
import com.amazonaws.services.simpleemail.model.RawMessage;
import com.amazonaws.services.simpleemail.model.SendRawEmailRequest;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * <p>Helper for building {@link RawMessage} requests for the common case of an HTML or
 * test email message with some attachments. For more details on Amazon's recommendations
 * see <a href="http://docs.aws.amazon.com/ses/latest/DeveloperGuide/send-email-raw.html">sending
 * raw email</a>. With this class the usage is much simpler, e.g. with the v1 SDK:</p>
 *
 * <pre>
 * AmazonSimpleEmailService client = ...
 * RawMessage message = new RawMessage().withData(
 *   new EmailRequestBuilder()
 *     .withFromAddress("bob@example.com")
 *     .withToAddresses("andrew@example.com")
 *     .withSubject("Test message")
 *     .withHtmlBody("&lt;html&gt;&lt;body&gt;&lt;h1&gt;Alert!&lt;/h1&gt;&lt;p&gt;&lt;img src=\"cid:my-image.png\"&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;")
 *     .addAttachment(Attachment.fromResource("image/png", "my-image.png"))
 *     .toByteBuffer()
 * );
 * client.sendRawEmail(new SendRawEmailRequest().withRawMessage(message));
 * </pre>
 *
 * <p>With the v2 SDK:</p>
 *
 * <pre>
 * SesClient client = SesClient.create();
 * SdkBytes data = SdkBytes.fromByteBuffer(
 *   new EmailRequestBuilder()
 *     .withFromAddress("bob@example.com")
 *     .withToAddresses("andrew@example.com")
 *     .withSubject("Test message")
 *     .withHtmlBody("&lt;html&gt;&lt;body&gt;&lt;h1&gt;Alert!&lt;/h1&gt;&lt;p&gt;&lt;img src=\"cid:my-image.png\"&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;")
 *     .addAttachment(Attachment.fromResource("image/png", "my-image.png"))
 *     .toByteBuffer()
 * );
 * SendRawEmailRequest request = SendRawEmailRequest.builder()
 *   .rawMessage(RawMessage.builder().data(data).build())
 *   .build();
 * client.sendRawEmail(request);
 * </pre>
 */
public final class EmailRequestBuilder {

    private String fromAddress;
    private String fromArn;
    private Destination destination;
    private List<String> replyToAddresses;
    private String subject;
    private String contentType;
    private String body;
    private List<Attachment> attachments;
    private String boundary;

    /** Create a new instance of the builder. */
    public EmailRequestBuilder() {
        destination = new Destination();
        replyToAddresses = Collections.emptyList();
        body = "";
        attachments = new ArrayList<>();
        boundary = UUID.randomUUID().toString();
    }

    /** For test cases we want a fixed boundary. */
    EmailRequestBuilder withBoundary(String boundary) {
        this.boundary = boundary;
        return this;
    }

    /**
     * Set the source or from address of the message. If not specified, then it must be
     * provided when constructing the {@code SendRawEmailRequest} object.
     *
     * @deprecated Use {@link #withFromAddress(String)} instead. Renamed to avoid confusion
     * as this will set the {@code From} header in the message which behaves differently than
     * calling {@code SendRawEmailRequest.withSource} when using sending authorization. Will
     * be removed in 2.0.
     */
    @Deprecated
    public EmailRequestBuilder withSource(String source) {
        return withFromAddress(source);
    }

    /**
     * Set the source or from address of the message. If not specified, then it must be
     * provided when constructing the {@code SendRawEmailRequest} object.
     */
    public EmailRequestBuilder withFromAddress(String address) {
        this.fromAddress = address;
        return this;
    }

    /**
     * Set the ARN of the identity that is associated with the sending authorization policy
     * that permits you to specify a particular "From" address in the header of the raw email.
     * The ARN will be encoded in the message with the {@code X-SES-FROM-ARN} header.
     */
    public EmailRequestBuilder withFromArn(String fromArn) {
        this.fromArn = fromArn;
        return this;
    }

    /** Set the destinations (to, cc, and bcc) for the message. */
    public EmailRequestBuilder withDestination(Destination destination) {
        this.destination = destination;
        return this;
    }

    /** Set the list of recipients for the message. */
    public EmailRequestBuilder withToAddresses(String... addresses) {
        destination.withToAddresses(addresses);
        return this;
    }

    /** Set the list of addresses to use for replies to the message. */
    public EmailRequestBuilder withReplyToAddresses(String... addresses) {
        this.replyToAddresses = Arrays.asList(addresses);
        return this;
    }

    /** Set the list of addresses to be copied on the message. */
    public EmailRequestBuilder withCcAddresses(String... addresses) {
        destination.withCcAddresses(addresses);
        return this;
    }

    /**
     * Set the list of addresses to be copied on the message without other recipients being
     * aware. This can be useful for privacy as well as minimizing spam for notification messages
     * if other recipients are likely to be uninterested in the replies (many have a habit of
     * reply all).
     */
    public EmailRequestBuilder withBccAddresses(String... addresses) {
        destination.withBccAddresses(addresses);
        return this;
    }

    /**
     * Sets the main message. Note the charset will be ignored and UTF-8 will get used.
     *
     * @deprecated Use {@link #withSubject(String)} and either {@link #withTextBody(String)}
     * or {@link #withHtmlBody(String)} instead. This allows the builder to be used with either
     * v1 or v2 of the AWS SDK for Java. In iep version 2.0 this method and the explicit dependency
     * on v1 of the AWS SDK will be removed.
     */
    @Deprecated
    public EmailRequestBuilder withMessage(Message message) {
        withSubject(message.getSubject().getData());
        Body body = message.getBody();
        if (body.getHtml() != null) {
            withHtmlBody(body.getHtml().getData());
        } else if (body.getText() != null) {
            withTextBody(body.getText().getData());
        }
        return this;
    }

    /** Sets the subject of the message. This field is required. */
    public EmailRequestBuilder withSubject(String subject) {
        this.subject = subject;
        return this;
    }

    /** Sets the body of the message using a content type of {@code text/html}. */
    public EmailRequestBuilder withHtmlBody(String body) {
        this.contentType = "text/html; charset=UTF-8";
        this.body = body;
        return this;
    }

    /** Sets the body of the message using a content type of {@code text/plain}. */
    public EmailRequestBuilder withTextBody(String body) {
        this.contentType = "text/plain; charset=UTF-8";
        this.body = body;
        return this;
    }

    /** Adds an attachment to the message. */
    public EmailRequestBuilder addAttachment(Attachment attachment) {
        attachments.add(attachment);
        return this;
    }

    private String encodeAddressList(List<String> addresses) {
        return addresses.stream().collect(Collectors.joining(", "));
    }

    /**
     * Creates the raw email request for use with
     * {@link com.amazonaws.services.simpleemail.AmazonSimpleEmailService#sendRawEmail(SendRawEmailRequest)}.
     *
     * @deprecated Use {@link #toByteBuffer()} instead and construct the {@code RawMessage}
     * object. This allows the builder to be used with either v1 or v2 of the AWS SDK for Java.
     * In iep version 2.0 this method and the explicit dependency on v1 of the AWS SDK will be
     * removed.
     */
    @Deprecated
    public SendRawEmailRequest build() {
        return new SendRawEmailRequest().withRawMessage(toRawMessage());
    }

    /**
     * Creates the {@link RawMessage}. Can be used if additional modifications to the message
     * are needed before creating the request object.
     *
     * @deprecated Use {@link #toByteBuffer()} instead and construct the {@code RawMessage}
     * object. This allows the builder to be used with either v1 or v2 of the AWS SDK for Java.
     * In iep version 2.0 this method and the explicit dependency on v1 of the AWS SDK will be
     * removed.
     */
    @Deprecated
    public RawMessage toRawMessage() {
        return new RawMessage().withData(toByteBuffer());
    }

    /**
     * Creates a {@link ByteBuffer} containing the MIME encoded raw message for the email.
     */
    public ByteBuffer toByteBuffer() {
        return ByteBuffer.wrap(toByteArray());
    }

    /**
     * Creates a byte array containing the MIME encoded raw message for the email.
     */
    public byte[] toByteArray() {
        return toString().getBytes(StandardCharsets.UTF_8);
    }

    /** Generates the MIME encoded string for the message. */
    @Override
    public String toString() {
        final String mimeBoundary = "--" + boundary;
        StringBuilder builder = new StringBuilder();

        if (subject == null || subject.isEmpty()) {
            throw new IllegalArgumentException("subject not specified");
        }

        // Can be specified by calling withSource on the SendRawEmailRequest object instead. That
        // is necessary if you want to use withSourceArn for sending authorization. If the source
        // is provided here, then withFromArn must be used instead.
        final String fromHeader = (fromAddress == null || fromAddress.isEmpty()) ? ""
                : EmailHeader.from(fromAddress).toString();

        final String to = encodeAddressList(destination.getToAddresses());
        if (to == null || to.isEmpty()) {
            throw new IllegalArgumentException("no recipients specified");
        }

        builder.append(EmailHeader.mime()).append(EmailHeader.multipart(boundary)).append(fromHeader)
                .append(EmailHeader.to(to)).append(EmailHeader.subject(subject));

        final String cc = encodeAddressList(destination.getCcAddresses());
        if (cc != null && !cc.isEmpty()) {
            builder.append(EmailHeader.cc(cc));
        }

        final String bcc = encodeAddressList(destination.getBccAddresses());
        if (bcc != null && !bcc.isEmpty()) {
            builder.append(EmailHeader.bcc(bcc));
        }

        final String replyTo = encodeAddressList(replyToAddresses);
        if (replyTo != null && !replyTo.isEmpty()) {
            builder.append(EmailHeader.replyTo(replyTo));
        }

        if (fromArn != null && !fromArn.isEmpty()) {
            builder.append(EmailHeader.fromArn(fromArn));
        }

        builder.append(EncodingUtils.CRLF).append(mimeBoundary).append(EncodingUtils.CRLF)
                .append(EmailHeader.contentType(contentType)).append(EmailHeader.contentTransferEncoding("base64"))
                .append(EncodingUtils.CRLF).append(EncodingUtils.base64(body.getBytes(StandardCharsets.UTF_8)))
                .append(EncodingUtils.CRLF);

        for (Attachment attachment : attachments) {
            builder.append(mimeBoundary).append(EncodingUtils.CRLF).append(attachment.toString());
        }

        builder.append(mimeBoundary).append("--").append(EncodingUtils.CRLF);
        return builder.toString();
    }
}