From 88a4949ef8051d6e785a2ab42a87ad2df08ddd00 Mon Sep 17 00:00:00 2001 From: Rachel Guan Date: Thu, 8 Jul 2021 12:03:03 -0400 Subject: [PATCH] Add cc support to email service (#1230) * Add cc support to email service --- .../google/registry/util/EmailMessage.java | 54 +++++++---- .../registry/util/SendEmailService.java | 10 +-- .../registry/util/SendEmailServiceTest.java | 90 ++++++++++++++++--- 3 files changed, 120 insertions(+), 34 deletions(-) diff --git a/util/src/main/java/google/registry/util/EmailMessage.java b/util/src/main/java/google/registry/util/EmailMessage.java index 646c06990..ac63d31d9 100644 --- a/util/src/main/java/google/registry/util/EmailMessage.java +++ b/util/src/main/java/google/registry/util/EmailMessage.java @@ -26,16 +26,6 @@ import javax.mail.internet.InternetAddress; @AutoValue public abstract class EmailMessage { - public abstract String subject(); - public abstract String body(); - public abstract ImmutableSet recipients(); - public abstract InternetAddress from(); - - public abstract ImmutableSet bccs(); - - public abstract Optional contentType(); - public abstract Optional attachment(); - public static Builder newBuilder() { return new AutoValue_EmailMessage.Builder(); } @@ -50,24 +40,48 @@ public abstract class EmailMessage { .build(); } + public abstract String subject(); + + public abstract String body(); + + public abstract ImmutableSet recipients(); + + public abstract InternetAddress from(); + + public abstract ImmutableSet ccs(); + + public abstract ImmutableSet bccs(); + + public abstract Optional contentType(); + + public abstract Optional attachment(); + /** Builder for {@link EmailMessage}. */ @AutoValue.Builder public abstract static class Builder { public abstract Builder setSubject(String subject); + public abstract Builder setBody(String body); + public abstract Builder setRecipients(Collection recipients); + public abstract Builder setFrom(InternetAddress from); public abstract Builder setBccs(Collection bccs); + public abstract Builder setCcs(Collection ccs); + public abstract Builder setContentType(MediaType contentType); + public abstract Builder setAttachment(Attachment attachment); abstract ImmutableSet.Builder recipientsBuilder(); abstract ImmutableSet.Builder bccsBuilder(); + abstract ImmutableSet.Builder ccsBuilder(); + public Builder addRecipient(InternetAddress value) { recipientsBuilder().add(value); return this; @@ -78,28 +92,36 @@ public abstract class EmailMessage { return this; } + public Builder addCc(InternetAddress cc) { + ccsBuilder().add(cc); + return this; + } + public abstract EmailMessage build(); } /** An attachment to the email, if one exists. */ @AutoValue public abstract static class Attachment { - - public abstract MediaType contentType(); - public abstract String filename(); - public abstract String content(); - public static Builder newBuilder() { return new AutoValue_EmailMessage_Attachment.Builder(); } + public abstract MediaType contentType(); + + public abstract String filename(); + + public abstract String content(); + /** Builder for {@link Attachment}. */ @AutoValue.Builder public abstract static class Builder { - public abstract Builder setContentType(MediaType contentType); + public abstract Builder setFilename(String filename); + public abstract Builder setContent(String content); + public abstract Attachment build(); } } diff --git a/util/src/main/java/google/registry/util/SendEmailService.java b/util/src/main/java/google/registry/util/SendEmailService.java index 362083d51..0a336e78f 100644 --- a/util/src/main/java/google/registry/util/SendEmailService.java +++ b/util/src/main/java/google/registry/util/SendEmailService.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.util.Properties; import javax.inject.Inject; import javax.inject.Singleton; +import javax.mail.Address; import javax.mail.BodyPart; import javax.mail.Message; import javax.mail.Message.RecipientType; @@ -50,8 +51,8 @@ public class SendEmailService { } /** - * Converts the provided message content into a {@link javax.mail.Message} and sends it with - * retry on transient failures. + * Converts the provided message content into a {@link javax.mail.Message} and sends it with retry + * on transient failures. */ public void sendEmail(EmailMessage emailMessage) { retrier.callWithRetry( @@ -78,9 +79,8 @@ public class SendEmailService { attachmentPart.setFileName(attachment.filename()); multipart.addBodyPart(attachmentPart); } - for (InternetAddress bcc : emailMessage.bccs()) { - msg.addRecipient(RecipientType.BCC, bcc); - } + msg.addRecipients(RecipientType.BCC, toArray(emailMessage.bccs(), Address.class)); + msg.addRecipients(RecipientType.CC, toArray(emailMessage.ccs(), Address.class)); msg.setContent(multipart); msg.saveChanges(); transportEmailSender.sendMessage(msg); diff --git a/util/src/test/java/google/registry/util/SendEmailServiceTest.java b/util/src/test/java/google/registry/util/SendEmailServiceTest.java index 95fb3c5a4..77cd1fbe1 100644 --- a/util/src/test/java/google/registry/util/SendEmailServiceTest.java +++ b/util/src/test/java/google/registry/util/SendEmailServiceTest.java @@ -68,7 +68,28 @@ class SendEmailServiceTest { } @Test - void testSuccess_bcc() throws Exception { + void testSuccess_addBccs() throws Exception { + EmailMessage.Builder contentBuilder = + EmailMessage.newBuilder() + .setFrom(new InternetAddress("test@example.com")) + .setSubject("test subject") + .setBody("test body"); + for (String email : + ImmutableList.of("bcc@example.com", "bcc1@example.com", "bcc2@example.com")) { + contentBuilder.addBcc(new InternetAddress(email)); + } + + sendEmailService.sendEmail(contentBuilder.build()); + assertThat(getMessage().getRecipients(RecipientType.BCC)) + .asList() + .containsExactly( + new InternetAddress("bcc@example.com"), + new InternetAddress("bcc1@example.com"), + new InternetAddress("bcc2@example.com")); + } + + @Test + void testSuccess_setBccs() throws Exception { EmailMessage content = createBuilder() .setBccs( @@ -77,19 +98,63 @@ class SendEmailServiceTest { new InternetAddress("bcc2@example.com"))) .build(); sendEmailService.sendEmail(content); - Message message = getMessage(); - assertThat(message.getRecipients(RecipientType.BCC)) + assertThat(getMessage().getRecipients(RecipientType.BCC)) .asList() .containsExactly( new InternetAddress("bcc@example.com"), new InternetAddress("bcc2@example.com")); } @Test - void testSuccess_contentType() throws Exception { - EmailMessage content = createBuilder().setContentType(MediaType.HTML_UTF_8).build(); + void testSuccess_emptyBcc() throws Exception { + sendEmailService.sendEmail(createBuilder().setBccs(ImmutableList.of()).build()); + assertThat(getMessage().getRecipients(RecipientType.BCC)).isNull(); + } + + @Test + void testSuccess_addCcs() throws Exception { + EmailMessage.Builder contentBuilder = EmailMessage.newBuilder(); + contentBuilder + .setFrom(new InternetAddress("test@example.com")) + .setSubject("test subject") + .setBody("test body"); + for (String email : ImmutableList.of("cc@example.com", "cc1@example.com", "cc2@example.com")) { + contentBuilder.addCc(new InternetAddress(email)); + } + sendEmailService.sendEmail(contentBuilder.build()); + assertThat(getMessage().getRecipients(RecipientType.CC)) + .asList() + .containsExactly( + new InternetAddress("cc@example.com"), + new InternetAddress("cc1@example.com"), + new InternetAddress("cc2@example.com")); + } + + @Test + void testSuccess_setCcs() throws Exception { + EmailMessage content = + createBuilder() + .setCcs( + ImmutableList.of( + new InternetAddress("cc@example.com"), new InternetAddress("cc2@example.com"))) + .build(); sendEmailService.sendEmail(content); - Message message = getMessage(); - assertThat(getInternalContent(message).getContentType()).isEqualTo("text/html; charset=utf-8"); + assertThat(getMessage().getRecipients(RecipientType.CC)) + .asList() + .containsExactly( + new InternetAddress("cc@example.com"), new InternetAddress("cc2@example.com")); + } + + @Test + void testSuccess_emptyCC() throws Exception { + sendEmailService.sendEmail(createBuilder().setCcs(ImmutableList.of()).build()); + assertThat(getMessage().getRecipients(RecipientType.CC)).isNull(); + } + + @Test + void testSuccess_contentType() throws Exception { + sendEmailService.sendEmail(createBuilder().setContentType(MediaType.HTML_UTF_8).build()); + assertThat(getInternalContent(getMessage()).getContentType()) + .isEqualTo("text/html; charset=utf-8"); } @Test @@ -117,17 +182,16 @@ class SendEmailServiceTest { .doNothing() .when(wrapper) .sendMessage(messageCaptor.capture()); - EmailMessage content = createBuilder().build(); - sendEmailService.sendEmail(content); + sendEmailService.sendEmail(createBuilder().build()); assertThat(messageCaptor.getValue().getSubject()).isEqualTo("Subject"); } @Test void testFailure_wrongExceptionType() throws Exception { doThrow(new RuntimeException("this is a runtime exception")).when(wrapper).sendMessage(any()); - EmailMessage content = createBuilder().build(); RuntimeException thrown = - assertThrows(RuntimeException.class, () -> sendEmailService.sendEmail(content)); + assertThrows( + RuntimeException.class, () -> sendEmailService.sendEmail(createBuilder().build())); assertThat(thrown).hasMessageThat().isEqualTo("this is a runtime exception"); } @@ -137,9 +201,9 @@ class SendEmailServiceTest { .doThrow(new MessagingException("second")) .when(wrapper) .sendMessage(any()); - EmailMessage content = createBuilder().build(); RuntimeException thrown = - assertThrows(RuntimeException.class, () -> sendEmailService.sendEmail(content)); + assertThrows( + RuntimeException.class, () -> sendEmailService.sendEmail(createBuilder().build())); assertThat(thrown).hasCauseThat().hasMessageThat().isEqualTo("second"); assertThat(thrown).hasCauseThat().isInstanceOf(MessagingException.class); }