foo.domaintest.email.EmailApiModule.java Source code

Java tutorial

Introduction

Here is the source code for foo.domaintest.email.EmailApiModule.java

Source

/**
 * Copyright 2014 Google Inc. All rights reserved.
 *
 * 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 foo.domaintest.email;

import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.CharStreams;
import foo.domaintest.action.Action;
import foo.domaintest.action.RequestModule;
import foo.domaintest.metrics.impl.MetricsModule;

import dagger.Module;
import dagger.Provides;

import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUploadException;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.annotation.Documented;
import java.util.Collections;
import java.util.Set;

import javax.inject.Qualifier;
import javax.inject.Singleton;
import javax.mail.MessagingException;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.InternetHeaders;

/** Dagger module for creating the email api actions. */
@Module(addsTo = RequestModule.class, includes = MetricsModule.class, injects = { AutoreplyAction.class })
public class EmailApiModule {

    public static final Set<Class<? extends Action>> ACTIONS = ImmutableSet
            .<Class<? extends Action>>of(AutoreplyAction.class);

    /** Binding annotation for all unparsed email headers. */
    @Qualifier
    @Documented
    public @interface RawEmailHeaders {
    }

    /** Binding annotation for parsed email headers. */
    @Qualifier
    @Documented
    public @interface EmailHeader {
        String value();
    }

    /**
     * Provides parsed email headers from the "headers" param in a multipart/form-data request.
     * <p>
     * Although SendGrid parses some headers for us, it doesn't parse "reply-to", so we need to do
     * this. Once we are doing it, it's easier to be consistent and use this as the sole source of
     * truth for information that originates in the headers.
     */
    @Provides
    @Singleton
    InternetHeaders provideHeaders(FileItemIterator iterator) {
        try {
            while (iterator != null && iterator.hasNext()) {
                FileItemStream item = iterator.next();
                // SendGrid sends us the headers in the "headers" param.
                if (item.getFieldName().equals("headers")) {
                    try (InputStream stream = item.openStream()) {
                        // SendGrid always sends headers in UTF-8 encoding.
                        return new InternetHeaders(new ByteArrayInputStream(
                                CharStreams.toString(new InputStreamReader(stream, UTF_8.name())).getBytes(UTF_8)));
                    }
                }
            }
        } catch (MessagingException | FileUploadException | IOException e) {
            // If we fail parsing the headers fall through returning the empty header object below.
        }
        return new InternetHeaders(); // Parsing failed or there was no "headers" param.
    }

    @Provides
    @RawEmailHeaders
    @SuppressWarnings("unchecked")
    String provideRawEmailHeaders(InternetHeaders headers) {
        return Joiner.on("\r\n").join(Collections.list(headers.getAllHeaderLines()));
    }

    @Provides
    @EmailHeader("from")
    String provideFrom(InternetHeaders headers) {
        return getAddressHeader(headers, "from");
    }

    @Provides
    @EmailHeader("reply-to")
    String provideReplyTo(InternetHeaders headers) {
        return getAddressHeader(headers, "reply-to");
    }

    @Provides
    @EmailHeader("to")
    String provideTo(InternetHeaders headers) {
        return getAddressHeader(headers, "to");
    }

    @Provides
    @EmailHeader("subject")
    String provideSubject(InternetHeaders headers) {
        return getHeader(headers, "subject");
    }

    @Provides
    @EmailHeader("message-id")
    String provideMessageId(InternetHeaders headers) {
        return getHeader(headers, "message-id");
    }

    @Provides
    @EmailHeader("references")
    String provideReferences(InternetHeaders headers) {
        return getHeader(headers, "references");
    }

    @Provides
    @EmailHeader("in-reply-to")
    String provideInReplyTo(InternetHeaders headers) {
        return getHeader(headers, "in-reply-to");
    }

    /** Parse an email from a header that may be of the form {@code First Last <name@example.tld>}. */
    public String getAddressHeader(InternetHeaders headers, String headerName) {
        try {
            String header = getHeader(headers, headerName);
            if (header == null) {
                return null;
            }
            // The "false" argument means use loose validation when parsing addresses out of the header.
            InternetAddress[] addresses = InternetAddress.parseHeader(header, false);
            return addresses == null || addresses.length == 0 ? null : addresses[0].getAddress();
        } catch (AddressException e) {
            return null;
        }
    }

    private String getHeader(InternetHeaders headers, String headerName) {
        // The "null" argument means ignore all but the first instance of the header.
        return headers.getHeader(headerName, null);
    }
}