package com.github.jaystgelais.easymail;
import javax.activation.DataHandler;
import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* Immutable wrapper around {@link javax.mail.Message} that provides transformation of HTML content for cross
* client compatibility.
*
* @author jaystgelais
*/
public final class EmailMessage {
private final Address from;
private final Set<Address> to;
private final Set<Address> cc;
private final Set<Address> bcc;
private final String subject;
private final String messageBody;
private final Collection<EmbeddedImageReference> imageDataSources;
private EmailMessage(final Builder builder) {
from = builder.from;
subject = builder.subject;
messageBody = builder.messageBody.getHtmlMessage();
to = Collections.unmodifiableSet(builder.to);
cc = Collections.unmodifiableSet(builder.cc);
bcc = Collections.unmodifiableSet(builder.bcc);
imageDataSources = Collections.unmodifiableCollection(builder.messageBody.getEmbeddedImages());
}
/**
* The email address representing this message's sender.
*
* @return The email address representing this message's sender.
*/
public Address getFrom() {
return from;
}
/**
* A collection of unique primary (to:) recipients.
*
* @return Set containing the email address of primary (to:) recipients.
*/
public Set<Address> getTo() {
return to;
}
/**
* A collection of unique carbon copy (cc:) recipients.
*
* @return Set containing the email address of carbon copy (cc:) recipients.
*/
public Set<Address> getCc() {
return cc;
}
/**
* A collection of unique blind carbon copy (cc:) recipients.
*
* @return Set containing the email address of blind carbon copy (cc:) recipients.
*/
public Set<Address> getBcc() {
return bcc;
}
/**
* The subject line of this email message.
*
* @return The subject line of this email message.
*/
public String getSubject() {
return subject;
}
/**
* The HTML document that will be sent as the message body of this email.
*
* @return String representing the HTML document that will be sent as the message body of this email.
*/
public String getMessageBody() {
return messageBody;
}
/**
* Send this email message.
*
* @param session Java Mail session providing connectivity to the outgoing mal server.
* @throws MessagingException If any errors occur that prevent the sending of this message.
*/
public void send(final Session session) throws MessagingException {
Message message = new MimeMessage(session);
message.setFrom(from);
message.setRecipients(Message.RecipientType.TO, to.toArray(new Address[0]));
message.setRecipients(Message.RecipientType.CC, cc.toArray(new Address[0]));
message.setRecipients(Message.RecipientType.BCC, bcc.toArray(new Address[0]));
message.setSubject(subject);
if (imageDataSources.isEmpty()) {
message.setContent(messageBody, "text/html");
} else {
Multipart multipart = new MimeMultipart("related");
BodyPart htmlPart = new MimeBodyPart();
htmlPart.setContent(messageBody, "text/html");
multipart.addBodyPart(htmlPart);
for (EmbeddedImageReference imageReference : imageDataSources) {
BodyPart imgPart = new MimeBodyPart();
imgPart.setDataHandler(new DataHandler(imageReference.getImageDataSource()));
imgPart.setHeader("Content-ID", imageReference.getContentId());
multipart.addBodyPart(imgPart);
}
message.setContent(multipart);
}
Transport.send(message);
}
/**
* Builder for instantiating new EmailMessages.
*/
public static final class Builder {
private final Address from;
private final Set<Address> to;
private final Set<Address> cc;
private final Set<Address> bcc;
private final String subject;
private final EmailMessageContent messageBody;
/**
* Creates a new EmailMessage Builder.
*
* @param from email address for the sender of this message
* @param subject Email Subject
* @param contentProvider content provider supplying untransformed HTML input
*
* @throws HtmlTransformationException If an error is encountered transforming Html content for inclusion in
* this email.
* @throws IllegalArgumentException If the email address supplied for {@code from} is not a valid
* email address.
*/
public Builder(final String from, final String subject,
final HtmlContentProvider contentProvider) throws HtmlTransformationException {
try {
this.from = new InternetAddress(from);
} catch (AddressException e) {
throw new IllegalArgumentException("Unable to parse [" + from + "] as a valid email address", e);
}
this.subject = subject;
this.messageBody = HtmlProcessor.process(contentProvider);
this.to = new HashSet<Address>();
this.cc = new HashSet<Address>();
this.bcc = new HashSet<Address>();
}
/**
* creates a new EmailMessage Builder.
*
* @param from email address for the sender of this message
* @param subject Email Subject
* @param htmlContent HTML content for message body
*
* @throws HtmlTransformationException If an error is encountered transforming Html content for inclusion in
* this email.
* @throws IllegalArgumentException If the email address supplied for {@code from} is not a valid
* email address.
*/
public Builder(final String from, final String subject,
final String htmlContent) throws HtmlTransformationException {
this(from, subject, new StaticHtmlContentProvider(htmlContent));
}
/**
* Adds email address to the set of primary (to:) recipients.
*
* @param address Email address to add to list of primary (to:) recipients.
* @return This Builder
* @throws IllegalArgumentException If address cannot be parsed into a valid email address.
*/
public Builder addTo(final String address) {
try {
to.add(new InternetAddress(address));
} catch (AddressException e) {
throw new IllegalArgumentException("Unable to parse [" + address + "] as a valid email address", e);
}
return this;
}
/**
* Adds email address to the set of carbon copy (cc:) recipients.
*
* @param address Email address to add to list of carbon copy (cc:) recipients.
* @return This Builder
* @throws IllegalArgumentException If address cannot be parsed into a valid email address.
*/
public Builder addCC(final String address) {
try {
cc.add(new InternetAddress(address));
} catch (AddressException e) {
throw new IllegalArgumentException("Unable to parse [" + address + "] as a valid email address", e);
}
return this;
}
/**
* Adds email address to the set of blind carbon copy (bcc:) recipients.
*
* @param address Email address to add to list of blind carbon copy (bcc:) recipients.
* @return This Builder
* @throws IllegalArgumentException If address cannot be parsed into a valid email address.
*/
public Builder addBCC(final String address) {
try {
bcc.add(new InternetAddress(address));
} catch (AddressException e) {
throw new IllegalArgumentException("Unable to parse [" + address + "] as a valid email address", e);
}
return this;
}
/**
* Returns an immutable EmailMessage initialized from data supplied to this builder.
*
* @return An immutable EmailMessage initialized from data supplied to this builder.
*/
public EmailMessage build() {
if (to.isEmpty() && cc.isEmpty() && bcc.isEmpty()) {
throw new IllegalStateException("At least one of TO, CC and BCC must be a non-empty set.");
}
return new EmailMessage(this);
}
}
}