-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add mailgun dependency * Add email clients from Shiba * Finalize sendEmail methods * Add tests to MailgunEmailClient * Add javadoc * Add setSenderEmail Co-authored-by: Bethany Seeger <bseeger@codeforamerica.org>
- Loading branch information
Showing
5 changed files
with
360 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package formflow.library.email; | ||
|
||
import java.io.File; | ||
import java.util.List; | ||
|
||
public interface EmailClient { | ||
|
||
/** | ||
* This sends an email with the least amount of information needed to be provided. | ||
* | ||
* @param subject The subject line of the email | ||
* @param recipientEmail The email address that will get the email, aka the To field | ||
* @param emailBody The plain text version of the email body | ||
*/ | ||
void sendEmail( | ||
String subject, | ||
String recipientEmail, | ||
String emailBody | ||
); | ||
|
||
/** | ||
* This sends an email with the least amount of information needed to be provided, but with attachments. | ||
* | ||
* @param subject The subject line of the email | ||
* @param recipientEmail The email address that will get the email, aka the To field | ||
* @param emailBody The plain text version of the email body | ||
* @param attachments A list of files that will be added as attachments to the email | ||
*/ | ||
void sendEmail( | ||
String subject, | ||
String recipientEmail, | ||
String emailBody, | ||
List<File> attachments | ||
); | ||
|
||
/** | ||
* This sends an email with the most customizations. | ||
* | ||
* @param subject The subject line of the email | ||
* @param recipientEmail The email address that will get the email, aka the To field | ||
* @param emailsToCC A list of emails to be added into the CC field | ||
* @param emailsToBCC A list of emails to be added into the BCC field | ||
* @param emailBody The plain text version of the email body | ||
* @param attachments A list of files that will be added as attachments to the email | ||
* @param requireTls A way to make TLS required | ||
*/ | ||
void sendEmail( | ||
String subject, | ||
String recipientEmail, | ||
List<String> emailsToCC, | ||
List<String> emailsToBCC, | ||
String emailBody, | ||
List<File> attachments, | ||
boolean requireTls | ||
); | ||
} |
146 changes: 146 additions & 0 deletions
146
src/main/java/formflow/library/email/MailgunEmailClient.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
package formflow.library.email; | ||
|
||
import com.mailgun.api.v3.MailgunMessagesApi; | ||
import com.mailgun.client.MailgunClient; | ||
import com.mailgun.model.message.Message; | ||
import feign.FeignException; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.io.File; | ||
import java.util.List; | ||
|
||
import static java.util.Collections.emptyList; | ||
|
||
@Component | ||
@Slf4j | ||
public class MailgunEmailClient implements EmailClient { | ||
|
||
private String senderEmail; | ||
private final String mailgunDomain; | ||
private MailgunMessagesApi mailgunMessagesApi; | ||
|
||
public MailgunEmailClient(@Value("${form-flow.email-client.mailgun.sender-email:}") String senderEmail, | ||
@Value("${form-flow.email-client.mailgun.domain:}") String mailgunDomain, | ||
@Value("${form-flow.email-client.mailgun.key:}") String mailgunKey | ||
) { | ||
this.senderEmail = senderEmail; | ||
this.mailgunDomain = mailgunDomain; | ||
this.mailgunMessagesApi = MailgunClient.config(mailgunKey) | ||
.createApi(MailgunMessagesApi.class); | ||
} | ||
|
||
/** | ||
* This sends an email with the least amount of information needed to be provided. | ||
* Sets empty or defaults to the rest of the parameters. | ||
* | ||
* @param subject The subject line of the email | ||
* @param recipientEmail The email address that will get the email, aka the To field | ||
* @param emailBody The plain text version of the email body | ||
*/ | ||
@Override | ||
public void sendEmail( | ||
String subject, | ||
String recipientEmail, | ||
String emailBody) { | ||
sendEmail( | ||
subject, | ||
recipientEmail, | ||
emptyList(), | ||
emptyList(), | ||
emailBody, | ||
emptyList(), | ||
false); | ||
} | ||
|
||
/** | ||
* This sends an email with the least amount of information needed to be provided, but with attachments. | ||
* Sets empty or defaults to the rest of the parameters. | ||
* | ||
* @param subject The subject line of the email | ||
* @param recipientEmail The email address that will get the email, aka the To field | ||
* @param emailBody The plain text version of the email body | ||
* @param attachments A list of files that will be added as attachments to the email | ||
*/ | ||
@Override | ||
public void sendEmail( | ||
String subject, | ||
String recipientEmail, | ||
String emailBody, | ||
List<File> attachments) { | ||
sendEmail( | ||
subject, | ||
recipientEmail, | ||
emptyList(), | ||
emptyList(), | ||
emailBody, | ||
attachments, | ||
false); | ||
} | ||
|
||
/** | ||
* The main method that sends to Mailgun. | ||
* Allows all parameter customization. | ||
* | ||
* @param subject The subject line of the email | ||
* @param recipientEmail The email address that will get the email, aka the To field | ||
* @param emailsToCC A list of emails to be added into the CC field | ||
* @param emailsToBCC A list of emails to be added into the BCC field | ||
* @param emailBody The plain text version of the email body | ||
* @param attachments A list of files that will be added as attachments to the email | ||
* @param requireTls A way to make TLS required | ||
*/ | ||
@Override | ||
public void sendEmail( | ||
String subject, | ||
String recipientEmail, | ||
List<String> emailsToCC, | ||
List<String> emailsToBCC, | ||
String emailBody, | ||
List<File> attachments, | ||
boolean requireTls) { | ||
Message.MessageBuilder message = Message.builder() | ||
.from(senderEmail) | ||
.to(recipientEmail) | ||
.subject(subject) | ||
.text(emailBody) | ||
.requireTls(requireTls); | ||
|
||
if (emailsToCC != null && !emailsToCC.isEmpty()) { | ||
message.cc(emailsToCC); | ||
} | ||
if (emailsToBCC != null && !emailsToBCC.isEmpty()) { | ||
message.bcc(emailsToBCC); | ||
} | ||
if (attachments != null && !attachments.isEmpty()) { | ||
message.attachment(attachments); | ||
} | ||
Message builtMessage = message.build(); | ||
|
||
try { | ||
mailgunMessagesApi.sendMessage(mailgunDomain, builtMessage); | ||
} catch (FeignException exception) { | ||
log.error(exception.getMessage()); | ||
} | ||
} | ||
|
||
/** | ||
* This setter allows us to replace mailgunMessageApi with a mock for testing. | ||
* | ||
* @param mailgunMessageApi The mailgunMessageApi you want to use to interface with Mailgun. | ||
*/ | ||
public void setMailgunMessagesApi(MailgunMessagesApi mailgunMessageApi) { | ||
this.mailgunMessagesApi = mailgunMessageApi; | ||
} | ||
|
||
/** | ||
* This setter allows you to change the senderEmail. | ||
* By default, senderEmail is defined in application.yaml. | ||
* | ||
* @param senderEmail The email that is used to fill the from field. | ||
*/ | ||
public void setSenderEmail(String senderEmail) { | ||
this.senderEmail = senderEmail; | ||
} | ||
} |
152 changes: 152 additions & 0 deletions
152
src/test/java/formflow/library/email/MailgunEmailClientTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
package formflow.library.email; | ||
|
||
import com.mailgun.api.v3.MailgunMessagesApi; | ||
import com.mailgun.model.message.Message; | ||
import formflow.library.utilities.AbstractMockMvcTest; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.mockito.ArgumentCaptor; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
|
||
import java.io.File; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat; | ||
import static org.mockito.ArgumentMatchers.any; | ||
import static org.mockito.Mockito.*; | ||
|
||
public class MailgunEmailClientTest extends AbstractMockMvcTest { | ||
|
||
@Autowired | ||
private MailgunEmailClient mailgunEmailClient; | ||
|
||
private final MailgunMessagesApi mailgunMessagesApi = mock(MailgunMessagesApi.class); | ||
|
||
@Override | ||
@BeforeEach | ||
public void setUp() throws Exception { | ||
mailgunEmailClient.setMailgunMessagesApi(mailgunMessagesApi); | ||
super.setUp(); | ||
} | ||
|
||
@Test | ||
public void mailgunWillSendWithMinimumInfo() throws Exception { | ||
final ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class); | ||
doReturn(null).when(mailgunMessagesApi).sendMessage(any(), captor.capture()); | ||
|
||
String expectedSubject = "sendEmail with no CC's or attachments"; | ||
String expectedRecipient = "test@example.com"; | ||
String expectedBody = "Email body"; | ||
|
||
mailgunEmailClient.sendEmail( | ||
expectedSubject, | ||
expectedRecipient, | ||
expectedBody | ||
); | ||
|
||
final Message builtMessage = captor.getValue(); | ||
assertThat(builtMessage).isNotNull(); | ||
assertThat(builtMessage.getSubject()).isEqualTo(expectedSubject); | ||
assertThat(builtMessage.getTo().contains(expectedRecipient)).isEqualTo(true); | ||
assertThat(builtMessage.getText()).isEqualTo(expectedBody); | ||
assertThat(builtMessage.getCc()).isNull(); | ||
assertThat(builtMessage.getBcc()).isNull(); | ||
assertThat(builtMessage.getAttachment()).isNull(); | ||
assertThat(builtMessage.getRequireTls()).isEqualTo("no"); | ||
} | ||
|
||
@Test | ||
public void mailgunWillSendWithDifferentSenderEmail() throws Exception { | ||
final ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class); | ||
doReturn(null).when(mailgunMessagesApi).sendMessage(any(), captor.capture()); | ||
|
||
String expectedSubject = "sendEmail with no CC's or attachments"; | ||
String expectedRecipient = "test@example.com"; | ||
String expectedBody = "Email body"; | ||
String expectedSenderEmail = "Another Sender <test@example.org>"; | ||
|
||
mailgunEmailClient.setSenderEmail(expectedSenderEmail); | ||
mailgunEmailClient.sendEmail( | ||
expectedSubject, | ||
expectedRecipient, | ||
expectedBody | ||
); | ||
|
||
final Message builtMessage = captor.getValue(); | ||
assertThat(builtMessage).isNotNull(); | ||
assertThat(builtMessage.getFrom()).isEqualTo(expectedSenderEmail); | ||
assertThat(builtMessage.getSubject()).isEqualTo(expectedSubject); | ||
assertThat(builtMessage.getTo().contains(expectedRecipient)).isEqualTo(true); | ||
assertThat(builtMessage.getText()).isEqualTo(expectedBody); | ||
assertThat(builtMessage.getCc()).isNull(); | ||
assertThat(builtMessage.getBcc()).isNull(); | ||
assertThat(builtMessage.getAttachment()).isNull(); | ||
assertThat(builtMessage.getRequireTls()).isEqualTo("no"); | ||
} | ||
|
||
|
||
@Test | ||
public void mailgunWillSendWithMinimumInfoAndAttachments() throws Exception { | ||
final ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class); | ||
doReturn(null).when(mailgunMessagesApi).sendMessage(any(), captor.capture()); | ||
|
||
String expectedSubject = "sendEmail with no CC's"; | ||
String expectedRecipient = "test@example.com"; | ||
String expectedBody = "Email body"; | ||
List<File> expectedAttachments = Arrays.asList(new File("src/test/resources/pdfs/blankPdf.pdf"), new File("src/test/resources/pdfs/testPdf.pdf")); | ||
|
||
mailgunEmailClient.sendEmail( | ||
expectedSubject, | ||
expectedRecipient, | ||
expectedBody, | ||
expectedAttachments | ||
); | ||
|
||
final Message builtMessage = captor.getValue(); | ||
assertThat(builtMessage).isNotNull(); | ||
assertThat(builtMessage.getSubject()).isEqualTo(expectedSubject); | ||
assertThat(builtMessage.getTo().contains(expectedRecipient)).isEqualTo(true); | ||
assertThat(builtMessage.getText()).isEqualTo(expectedBody); | ||
assertThat(builtMessage.getCc()).isNull(); | ||
assertThat(builtMessage.getBcc()).isNull(); | ||
assertThat(builtMessage.getAttachment().size()).isEqualTo(2); | ||
assertThat(builtMessage.getRequireTls()).isEqualTo("no"); | ||
} | ||
|
||
@Test | ||
public void mailgunWillSendAllProvidedInfo() throws Exception { | ||
final ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class); | ||
doReturn(null).when(mailgunMessagesApi).sendMessage(any(), captor.capture()); | ||
|
||
String expectedSubject = "sendEmail with all parameters"; | ||
String expectedRecipient = "test@example.com"; | ||
List<String> expectedEmailsToCC = Arrays.asList("one@test.com", "two@test.com", "three@test.com"); | ||
List<String> expectedEmailsToBCC = Arrays.asList("secret-one@test.com", "secret-two@test.com"); | ||
String expectedBody = "Email body"; | ||
List<File> expectedAttachments = Arrays.asList(new File("src/test/resources/pdfs/blankPdf.pdf")); | ||
Boolean expectedRequireTls = true; | ||
|
||
mailgunEmailClient.sendEmail( | ||
expectedSubject, | ||
expectedRecipient, | ||
expectedEmailsToCC, | ||
expectedEmailsToBCC, | ||
expectedBody, | ||
expectedAttachments, | ||
expectedRequireTls | ||
); | ||
|
||
final Message builtMessage = captor.getValue(); | ||
assertThat(builtMessage).isNotNull(); | ||
assertThat(builtMessage.getSubject()).isEqualTo(expectedSubject); | ||
assertThat(builtMessage.getTo().contains(expectedRecipient)).isEqualTo(true); | ||
assertThat(builtMessage.getText()).isEqualTo(expectedBody); | ||
assertThat(builtMessage.getCc()).isNotNull(); | ||
assertThat(builtMessage.getCc().size()).isEqualTo(3); | ||
assertThat(builtMessage.getBcc()).isNotNull(); | ||
assertThat(builtMessage.getBcc().size()).isEqualTo(2); | ||
assertThat(builtMessage.getAttachment().size()).isEqualTo(1); | ||
assertThat(builtMessage.getRequireTls()).isEqualTo("yes"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters