SendGridV2Sender.java
package fr.sii.ogham.email.sendgrid.v2.sender.impl;
import static fr.sii.ogham.core.util.LogUtils.logString;
import static fr.sii.ogham.email.sendgrid.SendGridConstants.DEFAULT_SENDGRID_IMPLEMENTATION_PRIORITY;
import static fr.sii.ogham.email.sendgrid.sender.EmailValidator.validate;
import java.io.IOException;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sendgrid.SendGrid;
import com.sendgrid.SendGridException;
import fr.sii.ogham.core.builder.priority.Priority;
import fr.sii.ogham.core.exception.MessageException;
import fr.sii.ogham.core.sender.AbstractSpecializedSender;
import fr.sii.ogham.email.attachment.Attachment;
import fr.sii.ogham.email.exception.handler.ContentHandlerException;
import fr.sii.ogham.email.message.Email;
import fr.sii.ogham.email.message.EmailAddress;
import fr.sii.ogham.email.message.Recipient;
import fr.sii.ogham.email.sendgrid.sender.SendGridSender;
import fr.sii.ogham.email.sendgrid.sender.exception.AttachmentReadException;
import fr.sii.ogham.email.sendgrid.v2.sender.impl.sendgrid.client.SendGridClient;
import fr.sii.ogham.email.sendgrid.v2.sender.impl.sendgrid.client.SendGridInterceptor;
import fr.sii.ogham.email.sendgrid.v2.sender.impl.sendgrid.handler.SendGridContentHandler;
/**
* SendGrid-backed implementation of the email sender.
*/
@Priority(properties = "${ogham.email.implementation-priority.sendgrid}", defaultValue = DEFAULT_SENDGRID_IMPLEMENTATION_PRIORITY)
public final class SendGridV2Sender extends AbstractSpecializedSender<Email> implements SendGridSender {
private static final Logger LOG = LoggerFactory.getLogger(SendGridV2Sender.class);
private static final Pattern CID = Pattern.compile("^<(.+)>$");
private final SendGridClient delegate;
private final SendGridContentHandler handler;
private final SendGridInterceptor interceptor;
/**
* Constructor.
*
* @param service
* the underlying SendGrid service
* @param handler
* the content handler, in change of converting the email content
* into something the {@link SendGridClient} can work with
*/
public SendGridV2Sender(final SendGridClient service, final SendGridContentHandler handler) {
this(service, handler, null);
}
/**
* Constructor.
*
* @param service
* the underlying SendGrid service
* @param handler
* the content handler, in change of converting the email content
* into something the {@link SendGridClient} can work with
* @param interceptor
* an extension point for customizing the email to send
*/
public SendGridV2Sender(final SendGridClient service, final SendGridContentHandler handler, SendGridInterceptor interceptor) {
if (service == null) {
throw new IllegalArgumentException("[service] cannot be null");
}
if (handler == null) {
throw new IllegalArgumentException("[handler] cannot be null");
}
this.delegate = service;
this.handler = handler;
this.interceptor = interceptor;
}
@Override
public void send(final Email message) throws MessageException {
if (message == null) {
throw new IllegalArgumentException("[message] cannot be null");
}
validate(message);
try {
LOG.debug("Preparing to send email using SendGrid: {}", logString(message));
final SendGrid.Email sgEmail = intercept(toSendGridEmail(message), message);
LOG.debug("Sending email...\n{}", logString(message));
LOG.trace("SendGrid email: {}", sgEmail);
delegate.send(sgEmail);
LOG.debug("Email has been successfully sent");
} catch (ContentHandlerException e) {
throw new MessageException("A content-related error occurred when trying to build an email", message, e);
} catch (AttachmentReadException e) {
throw new MessageException("Attaching file to email failed when trying to send an email", message, e);
} catch (SendGridException e) {
throw new MessageException("A SendGrid-related error occurred when trying to send an email", message, e);
}
}
private SendGrid.Email intercept(SendGrid.Email sendGridEmail, Email source) {
if (interceptor == null) {
return sendGridEmail;
}
return interceptor.intercept(sendGridEmail, source);
}
private SendGrid.Email toSendGridEmail(final Email message) throws ContentHandlerException, AttachmentReadException {
final SendGrid.Email ret = new SendGrid.Email();
ret.setSubject(message.getSubject());
ret.setFrom(message.getFrom().getAddress());
ret.setFromName(message.getFrom().getPersonal() == null ? "" : message.getFrom().getPersonal());
final String[] tos = new String[message.getRecipients().size()];
final String[] toNames = new String[message.getRecipients().size()];
int i = 0;
for (Recipient recipient : message.getRecipients()) {
final EmailAddress address = recipient.getAddress();
tos[i] = address.getAddress();
toNames[i] = address.getPersonal() == null ? "" : address.getPersonal();
i++;
}
ret.setTo(tos);
ret.setToName(toNames);
handler.setContent(message, ret, message.getContent());
for (Attachment attachment : message.getAttachments()) {
addAttachment(ret, attachment);
}
return ret;
}
private static void addAttachment(final SendGrid.Email ret, final Attachment attachment) throws AttachmentReadException {
try {
ret.addAttachment(attachment.getResource().getName(), attachment.getResource().getInputStream());
// TODO: how to set Content-Type per attachment with SendGrid v2 API ?
if (attachment.getContentId() != null) {
String id = CID.matcher(attachment.getContentId()).replaceAll("$1");
ret.addContentId(attachment.getResource().getName(), id);
}
} catch (IOException e) {
throw new AttachmentReadException("Failed to attach email attachment named " + attachment.getResource().getName(), attachment, e);
}
}
public SendGridClient getDelegate() {
return delegate;
}
}