Package elasticemail

Source Code of elasticemail.ElasticEmailClient$ElasticEmailProperties

package elasticemail;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.List;
import java.util.Vector;

import nanoxml.XMLElement;
import nanoxml.XMLParseException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ElasticEmailClient {

  final static private Logger logger = LoggerFactory.getLogger(ElasticEmailClient.class);

  final static private String API_SEND = "https://api.elasticemail.com/mailer/send";
  final static private String API_UPLOAD_ATTACHMENT = "https://api.elasticemail.com/attachments/upload";
  final static private String API_STATUS = "https://api.elasticemail.com/mailer/status";
  final static private String UTF8 = "UTF-8";

  private ElasticEmailProperties props;

  /**
   * <p>
   * You will pass an implementation of this interface in order to supply the credentials needed for the Elastic Email
   * API.
   * </p>
   *
   * @author broc.seib@gmail.com
   */
  public interface ElasticEmailProperties {
    /**
     * @return the Elastic Email API username. It is probably an email address.
     */
    public String getElasticEmailUserName();

    /**
     * @return the Elastic Email API Key. It looks like a hash string.
     */
    public String getElasticEmailApiKey();
  }

  /**
   * <p>
   * Create an instance of a client that can speak to the Elastic Email service in the cloud.
   * </p>
   *
   * <p>
   * As for its statefulness, the reference 'props' that you pass it is kept as a member variable, but that's all. No
   * other state is kept. So you can keep a single instance of this class around, or re-instantiate it with the same
   * props if you wish next time you need it.
   * </p>
   *
   * @param props
   *        {@link ElasticEmailProperties} credentials needed to communicate with the Elastic Email API
   */
  public ElasticEmailClient(ElasticEmailProperties props) {
    this.props = props;
  }

  /**
   * <p>
   * Sends a plain text email.
   * </p>
   *
   * <p>
   * This will send an outbound email via Elastic Email. Note that you must have already set up Elastic Email via
   * their website to send emails from a particular domain, and your "from" fields need to match that domain.
   * </p>
   *
   * @param channel
   *        This is an arbitrary string so that you can run reports at Elastic Email and bucket your outbound email
   *        statistics. Pass null to ignore.
   * @param fromEmail
   *        This is the email address that the email will be "from".
   * @param fromName
   *        This is the human readable name of the person (or bot) the email will be "from".
   * @param toEmails
   *        This is a semicolon separated list of email recipients.
   * @param subject
   *        This is the Subject line of the email.
   * @param bodyText
   *        This is the plain text body of the email.
   * @return A transactionId string is returned, which can be passed to {@link #getStatus(String)} to check the status
   *         of your message delivery.
   * @throws IOException
   *         The Elastic Email API is over HTTP. If any communication goes awry, you'll get an IOException.
   */
  public TransactionId sendEmail(String channel, String fromEmail, String fromName, String toEmails, String subject, String bodyText) throws IOException {
    return sendEmail(channel, fromEmail, fromName, toEmails, subject, bodyText, null, null);
  }

  /*
   * toEmails is a semi colon separated list of email recipients**
   */

  /**
   * <p>
   * Sends an email with both plain text and html versions available for the client to choose to display. Attachments
   * can be made as well.
   * </p>
   *
   * <p>
   * This implementation was updated 10/26/2011 per this:
   * http://stackoverflow.com/questions/2793150/how-to-use-java-net-urlconnection-to-fire-and-handle-http-requests
   * </p>
   *
   * @param channel
   *        This is an arbitrary string so that you can run reports at Elastic Email and bucket your outbound email
   *        statistics. Pass null to ignore.
   * @param fromEmail
   *        This is the email address that the email will be "from".
   * @param fromName
   *        This is the human readable name of the person (or bot) the email will be "from".
   * @param toEmails
   *        This is a semicolon separated list of email recipients.
   * @param subject
   *        This is the Subject line of the email.
   * @param bodyText
   *        This is the plain text body of the email.
   * @param bodyHtml
   *        This is the html version of the email body. Pass null to not supply an html version of the body.
   * @param attachmentIds
   *        If you have any attachments, list them here. They must be uploaded in advance by calling
   *        {@link #uploadAttachment(InputStream, String)}.
   * @return
   * @throws IOException
   *         The Elastic Email API is over HTTP. If any communication goes awry, you'll get an IOException.
   */
  public TransactionId sendEmail(String channel, String fromEmail, String fromName, String toEmails, String subject, String bodyText, String bodyHtml, List<AttachmentId> attachmentIds)
      throws IOException {
    StringBuilder buf = new StringBuilder();
    buf.append("username=").append(urlEncodeUTF8(props.getElasticEmailUserName()));
    buf.append("&api_key=").append(urlEncodeUTF8(props.getElasticEmailApiKey()));
    buf.append("&from=").append(urlEncodeUTF8(fromEmail));
    buf.append("&from_name=").append(urlEncodeUTF8(fromName));
    buf.append("&to=").append(urlEncodeUTF8(toEmails));
    buf.append("&subject=").append(urlEncodeUTF8(subject));
    buf.append("&body_text=").append(urlEncodeUTF8(bodyText));
    if ( channel != null ) {
      buf.append("&channel=").append(urlEncodeUTF8(channel));
    }
    if ( bodyHtml != null ) {
      buf.append("&body_html=").append(urlEncodeUTF8(bodyHtml));
    }
    if ( attachmentIds != null ) {
      buf.append("&attachments=");
      for ( int i = 0; i < attachmentIds.size(); i++ ) {
        if ( i > 0 ) {
          buf.append(";");
        }
        buf.append(urlEncodeUTF8(attachmentIds.get(i).getId()));
      }
    }

    URL resturl = new URL(API_SEND);
    URLConnection con = resturl.openConnection();
    con.setDoOutput(true); // FYI, this implicitly sets req method to POST
    // con.setRequestMethod("POST");
    con.setRequestProperty("Accept-Charset", UTF8);
    con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + UTF8);
    OutputStream out = null;
    try {
      out = con.getOutputStream();
      out.write(buf.toString().getBytes(UTF8));
    }
    finally {
      if ( out != null ) {
        try {
          out.close();
        }
        catch ( IOException e ) { /* punt */}
      }
    }

    // done writing. now read.

    // get result code
    int responseCode = ((HttpURLConnection) con).getResponseCode();
    logger.info("email sent. response={} to={}, from={}, subject={}", responseCode, toEmails, fromEmail, subject);
    if ( responseCode != 200 ) {
      throw new IOException("bad response code: " + responseCode);
    }

    // the following call is what actually fires the HTTP request.
    InputStream response = con.getInputStream();
    BufferedReader in = null;
    try {
      in = new BufferedReader(new InputStreamReader(response, UTF8));
      String transactionId = in.readLine(); // only expect a single line
      // System.out.println("got back txId = " +transactionId);
      return new TransactionId(transactionId);
    }
    catch ( IOException e ) {
      throw new IOException("Unable to read response from server for sendEmail.");
    }
    finally {
      if ( in != null ) {
        try {
          in.close();
        }
        catch ( IOException e ) { /* punt */}
      }
    }
  }

  /**
   * <p>
   * Upload an email attachment.
   * </p>
   *
   * <p>
   * Attachments must be uploaded in advance of sending out email messages. Each uploaded attachment is assigned an
   * {@link AttachmentId}, which will be referred to when sending a message with an attachment.
   * </p>
   *
   * @param data
   *        Supply a binary of your attachment, in the form of an InputStream.
   * @param filename
   *        Provide a name for your attachment. Use the obvious file extensions, as they will likely help on the
   *        client side when the attachment is received.
   * @return The {@link AttachmentId} returned will be used in
   *         {@link #sendEmail(String, String, String, String, String, String, String, List)} to specify the
   *         attachment(s) to be used for the message.
   * @throws IOException
   *         The Elastic Email API is over HTTP. If any communication goes awry, you'll get an IOException.
   */
  public AttachmentId uploadAttachment(InputStream data, String filename) throws IOException {
    StringBuilder params = new StringBuilder();
    params.append("?username=").append(urlEncodeUTF8(props.getElasticEmailUserName()));
    params.append("&api_key=").append(urlEncodeUTF8(props.getElasticEmailApiKey()));
    params.append("&file=").append(urlEncodeUTF8(filename));

    URL resturl = new URL(API_UPLOAD_ATTACHMENT + params.toString());
    HttpURLConnection con = (HttpURLConnection) resturl.openConnection();
    con.setDoOutput(true); // FYI, this implicitly sets req method to POST
    con.setRequestMethod("PUT");
    con.setRequestProperty("Accept-Charset", UTF8);
    con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + UTF8);
    OutputStream out = null;
    try {
      final int BUFSIZ = 64 * 1024; // why not have a 64K buffer?
      byte[] buffer = new byte[BUFSIZ];
      int bytesRead = 0;

      out = con.getOutputStream();
      int total = 0;
      while ( (bytesRead = data.read(buffer, 0, BUFSIZ)) > 0 ) {
        out.write(buffer, 0, bytesRead);
        total += bytesRead;
      }
      logger.debug("total bytes uploaded: {}", total);
    }
    finally {
      if ( out != null ) {
        try {
          out.close();
        }
        catch ( IOException e ) { /* punt */}
      }
    }

    // done writing. now read.

    // get result code
    int responseCode = ((HttpURLConnection) con).getResponseCode();
    logger.debug("upload attachment response code = {}", responseCode);
    if ( responseCode != 200 ) {
      throw new IOException("bad response code: " + responseCode);
    }

    // the following call is what actually fires the HTTP request.
    InputStream response = con.getInputStream();
    BufferedReader in = null;
    try {
      in = new BufferedReader(new InputStreamReader(response, UTF8));
      String attachmentId = in.readLine(); // only expect a single line
      logger.debug("got back attachmentId = {}", attachmentId);
      return new AttachmentId(attachmentId);
    }
    catch ( IOException e ) {
      throw new IOException("Unable to read response from server for sendEmail.");
    }
    finally {
      if ( in != null ) {
        try {
          in.close();
        }
        catch ( IOException e ) { /* punt */}
      }
    }
  }

  /**
   * <p>
   * Poll the status of an outbound message.
   * </p>
   *
   * @param transactionId
   *        This is a TransactionId that you were given when you made the call to send the outbound message.
   * @return {@link MailerStatus}, which contains counters for number delivered, bounced, etc. But for now, this class
   *         ({@link ElasticEmailClient}) is setup to only send out messages one at a time, so the value returned in
   *         one of the fields of MailerStatus should only be a 1.
   * @throws IOException
   *         The Elastic Email API is over HTTP. If any communication goes awry, you'll get an IOException.
   */
  public MailerStatus getStatus(TransactionId transactionId) throws IOException, ElasticEmailException {
    StringBuilder buf = new StringBuilder();
    buf.append(API_STATUS).append("/").append(transactionId.getId()).append("?showstats=true");
    // buf.append("&username=").append(urlEncodeUTF8(USERNAME));
    // buf.append("&api_key=").append(urlEncodeUTF8(API_KEY));
    // System.out.println("status url: "+buf.toString());
    URL resturl = new URL(buf.toString());
    HttpURLConnection con = (HttpURLConnection) resturl.openConnection();
    con.setDoOutput(true);
    con.setRequestMethod("GET");
    OutputStreamWriter out = new OutputStreamWriter(con.getOutputStream());
    out.flush();
    out.close();

    BufferedReader in = null;
    try {
      if ( con.getInputStream() != null ) {
        in = new BufferedReader(new InputStreamReader(con.getInputStream()));
      }
    }
    catch ( IOException e ) {
      if ( con.getErrorStream() != null ) {
        in = new BufferedReader(new InputStreamReader(con.getErrorStream()));
      }
    }

    if ( in == null ) {
      throw new IOException("Unable to read response from server for getStatus.");
    }
    String response = getStringFromBufferedReader(in);
    in.close();
   
    int responseCode = con.getResponseCode();
    if ( (responseCode >= 200) || (responseCode < 300 ) ) {
      if ( response.startsWith("<") ) {
        return parseXmlReponse(response);
      }
      else {
        throw new ElasticEmailException(response);
      }
    }
    else {
      throw new ElasticEmailException(response);
    }
  }

  private MailerStatus parseXmlReponse(String response) {
    XMLElement xml = new XMLElement();
    try {
      xml.parseString(response);
      // System.out.println(xml);

      MailerStatus status = new MailerStatus();
      @SuppressWarnings("rawtypes")
      Vector children = xml.getChildren();
      for ( Object c : children ) {
        XMLElement x = (XMLElement) c;
        if ( "status".equals(x.getName()) ) {
          DeliveryStatus ds = DeliveryStatus.valueOf(x.getContent());
          status.setStatus(ds);
        }
        else {
          int val = Integer.parseInt(x.getContent());
          if ( "recipients".equals(x.getName()) ) {
            status.setRecipients(val);
          }
          else if ( "delivered".equals(x.getName()) ) {
            status.setDelivered(val);
          }
          else if ( "failed".equals(x.getName()) ) {
            status.setFailed(val);
          }
          else if ( "pending".equals(x.getName()) ) {
            status.setPending(val);
          }
          else if ( "opened".equals(x.getName()) ) {
            status.setOpened(val);
          }
          else if ( "clicked".equals(x.getName()) ) {
            status.setClicked(val);
          }
          else if ( "unsubscribed".equals(x.getName()) ) {
            status.setUnsubscribed(val);
          }
          else if ( "abusereports".equals(x.getName()) ) {
            status.setAbusereports(val);
          }
        }
      }

      return status;
    }
    catch ( XMLParseException e ) {
      logger.error("could not parse response as xml: {}", response);
      throw e;
    }
  }

  private static String getStringFromBufferedReader(BufferedReader br) {
    StringBuilder sb = new StringBuilder();
    String line;
    try {
      while ( (line = br.readLine()) != null ) {
        sb.append(line);
      }

    }
    catch ( IOException e ) {
      e.printStackTrace();
    }
    finally {
      if ( br != null ) {
        try {
          br.close();
        }
        catch ( IOException e ) {
          e.printStackTrace();
        }
      }
    }
    return sb.toString();
  }

  /**
   * <p>
   * Convenience function to always url encode with UTF-8.
   * </p>
   *
   * @param url
   *        The URL to be encoded
   * @return UTF-8 encoded URL
   */
  static private String urlEncodeUTF8(String url) {
    try {
      return URLEncoder.encode(url, "UTF-8");
    }
    catch ( UnsupportedEncodingException e ) {
      throw new RuntimeException("Can't encode url as UTF-8: " + url);
    }
  }

}
TOP

Related Classes of elasticemail.ElasticEmailClient$ElasticEmailProperties

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.