From f65dba8ec5aa4e3ccf41553ece39e093360881b2 Mon Sep 17 00:00:00 2001 From: Pavlo Tkach <3469726+ptkach@users.noreply.github.com> Date: Thu, 25 Aug 2022 14:15:20 -0400 Subject: [PATCH] Add registry email to bcc for outgoing DNS failure emails (#1755) --- .../registry/config/RegistryConfig.java | 10 +++- .../config/RegistryConfigSettings.java | 1 + .../registry/config/files/default-config.yaml | 1 + .../registry/dns/PublishDnsUpdatesAction.java | 54 +++++++++++++++---- .../dns/PublishDnsUpdatesActionTest.java | 33 +++++++----- 5 files changed, 72 insertions(+), 27 deletions(-) diff --git a/core/src/main/java/google/registry/config/RegistryConfig.java b/core/src/main/java/google/registry/config/RegistryConfig.java index 78cbf43cb..773222ced 100644 --- a/core/src/main/java/google/registry/config/RegistryConfig.java +++ b/core/src/main/java/google/registry/config/RegistryConfig.java @@ -1320,8 +1320,14 @@ public final class RegistryConfig { @Provides @Config("registrySupportEmail") - public static String provideRegistrySupportEmail(RegistryConfigSettings config) { - return config.dnsUpdate.registrySupportEmail; + public static InternetAddress provideRegistrySupportEmail(RegistryConfigSettings config) { + return parseEmailAddress(config.dnsUpdate.registrySupportEmail); + } + + @Provides + @Config("registryCcEmail") + public static InternetAddress provideRegistryCcEmail(RegistryConfigSettings config) { + return parseEmailAddress(config.dnsUpdate.registryCcEmail); } @Provides diff --git a/core/src/main/java/google/registry/config/RegistryConfigSettings.java b/core/src/main/java/google/registry/config/RegistryConfigSettings.java index bcbd84bb9..e027d2884 100644 --- a/core/src/main/java/google/registry/config/RegistryConfigSettings.java +++ b/core/src/main/java/google/registry/config/RegistryConfigSettings.java @@ -254,5 +254,6 @@ public class RegistryConfigSettings { public String dnsUpdateFailEmailBodyText; public String dnsUpdateFailRegistryName; public String registrySupportEmail; + public String registryCcEmail; } } diff --git a/core/src/main/java/google/registry/config/files/default-config.yaml b/core/src/main/java/google/registry/config/files/default-config.yaml index d8f624cc2..65fee09e3 100644 --- a/core/src/main/java/google/registry/config/files/default-config.yaml +++ b/core/src/main/java/google/registry/config/files/default-config.yaml @@ -481,6 +481,7 @@ contactHistory: dnsUpdate: dnsUpdateFailRegistryName: Example name registrySupportEmail: email@example.com + registryCcEmail: email@example.com # Email subject text template to notify partners after repeatedly failing DNS update dnsUpdateFailEmailSubjectText: "[ACTION REQUIRED]: Incomplete DNS Update" # Email body text template for failing DNS update that accepts 5 parameters: diff --git a/core/src/main/java/google/registry/dns/PublishDnsUpdatesAction.java b/core/src/main/java/google/registry/dns/PublishDnsUpdatesAction.java index 4bef5b88f..08371079f 100644 --- a/core/src/main/java/google/registry/dns/PublishDnsUpdatesAction.java +++ b/core/src/main/java/google/registry/dns/PublishDnsUpdatesAction.java @@ -34,6 +34,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMultimap; import com.google.common.flogger.FluentLogger; import com.google.common.net.InternetDomainName; +import dagger.Lazy; import google.registry.config.RegistryConfig.Config; import google.registry.dns.DnsMetrics.ActionStatus; import google.registry.dns.DnsMetrics.CommitStatus; @@ -52,14 +53,16 @@ import google.registry.request.Parameter; import google.registry.request.Response; import google.registry.request.auth.Auth; import google.registry.request.lock.LockHandler; -import google.registry.ui.server.SendEmailUtils; import google.registry.util.Clock; import google.registry.util.CloudTasksUtils; import google.registry.util.DomainNameUtils; +import google.registry.util.EmailMessage; +import google.registry.util.SendEmailService; import java.util.Optional; import java.util.Set; import java.util.concurrent.Callable; import javax.inject.Inject; +import javax.mail.internet.InternetAddress; import org.joda.time.DateTime; import org.joda.time.Duration; @@ -109,11 +112,13 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable { private final Clock clock; private final CloudTasksUtils cloudTasksUtils; private final Response response; - private final SendEmailUtils sendEmailUtils; + private final SendEmailService sendEmailService; private final String dnsUpdateFailEmailSubjectText; private final String dnsUpdateFailEmailBodyText; private final String dnsUpdateFailRegistryName; - private final String registrySupportEmail; + private final Lazy registrySupportEmail; + private final Lazy registryCcEmail; + private final InternetAddress gSuiteOutgoingEmailAddress; @Inject public PublishDnsUpdatesAction( @@ -129,7 +134,9 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable { @Config("dnsUpdateFailEmailSubjectText") String dnsUpdateFailEmailSubjectText, @Config("dnsUpdateFailEmailBodyText") String dnsUpdateFailEmailBodyText, @Config("dnsUpdateFailRegistryName") String dnsUpdateFailRegistryName, - @Config("registrySupportEmail") String registrySupportEmail, + @Config("registrySupportEmail") Lazy registrySupportEmail, + @Config("registryCcEmail") Lazy registryCcEmail, + @Config("gSuiteOutgoingEmailAddress") InternetAddress gSuiteOutgoingEmailAddress, @Header(APP_ENGINE_RETRY_HEADER) Optional appEngineRetryCount, @Header(CLOUD_TASKS_RETRY_HEADER) Optional cloudTasksRetryCount, DnsQueue dnsQueue, @@ -138,13 +145,13 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable { LockHandler lockHandler, Clock clock, CloudTasksUtils cloudTasksUtils, - SendEmailUtils sendEmailUtils, + SendEmailService sendEmailService, Response response) { this.dnsQueue = dnsQueue; this.dnsWriterProxy = dnsWriterProxy; this.dnsMetrics = dnsMetrics; this.timeout = timeout; - this.sendEmailUtils = sendEmailUtils; + this.sendEmailService = sendEmailService; this.retryCount = cloudTasksRetryCount.orElse( appEngineRetryCount.orElseThrow( @@ -165,6 +172,8 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable { this.dnsUpdateFailEmailSubjectText = dnsUpdateFailEmailSubjectText; this.dnsUpdateFailRegistryName = dnsUpdateFailRegistryName; this.registrySupportEmail = registrySupportEmail; + this.registryCcEmail = registryCcEmail; + this.gSuiteOutgoingEmailAddress = gSuiteOutgoingEmailAddress; } private void recordActionResult(ActionStatus status) { @@ -267,25 +276,48 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable { return null; } + private InternetAddress emailToInternetAddress(String email) { + try { + return new InternetAddress(email, true); + } catch (Exception e) { + logger.atWarning().withCause(e).log( + String.format( + "Could not parse email contact %s to send DNS failure notification", email)); + return null; + } + } + /** Sends an email to partners regarding a failure during DNS update */ private void notifyWithEmailAboutDnsUpdateFailure( String registrarId, String hostOrDomainName, Boolean isHost) { Optional registrar = Registrar.loadByRegistrarIdCached(registrarId); if (registrar.isPresent()) { - sendEmailUtils.sendEmail( - dnsUpdateFailEmailSubjectText, + String body = String.format( dnsUpdateFailEmailBodyText, registrar.get().getRegistrarName(), hostOrDomainName, isHost ? "host" : "domain", - registrySupportEmail, - dnsUpdateFailRegistryName), + registrySupportEmail.get().getAddress(), + dnsUpdateFailRegistryName); + + ImmutableList recipients = registrar.get().getContacts().stream() .filter(c -> c.getTypes().contains(RegistrarPoc.Type.ADMIN)) .map(RegistrarPoc::getEmailAddress) - .collect(toImmutableList())); + .map(this::emailToInternetAddress) + .collect(toImmutableList()); + + sendEmailService.sendEmail( + EmailMessage.newBuilder() + .setBody(body) + .setSubject(dnsUpdateFailEmailSubjectText) + .setRecipients(recipients) + .addBcc(registryCcEmail.get()) + .setFrom(gSuiteOutgoingEmailAddress) + .build()); + } else { logger.atSevere().log(String.format("Could not find registrar %s", registrarId)); } diff --git a/core/src/test/java/google/registry/dns/PublishDnsUpdatesActionTest.java b/core/src/test/java/google/registry/dns/PublishDnsUpdatesActionTest.java index dce6e0c61..00722d23d 100644 --- a/core/src/test/java/google/registry/dns/PublishDnsUpdatesActionTest.java +++ b/core/src/test/java/google/registry/dns/PublishDnsUpdatesActionTest.java @@ -38,9 +38,9 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import dagger.Lazy; import google.registry.dns.DnsMetrics.ActionStatus; import google.registry.dns.DnsMetrics.CommitStatus; import google.registry.dns.DnsMetrics.PublishStatus; @@ -55,7 +55,7 @@ import google.registry.testing.CloudTasksHelper.TaskMatcher; import google.registry.testing.FakeClock; import google.registry.testing.FakeLockHandler; import google.registry.testing.FakeResponse; -import google.registry.ui.server.SendEmailUtils; +import google.registry.testing.Lazies; import google.registry.util.EmailMessage; import google.registry.util.SendEmailService; import java.util.Optional; @@ -83,19 +83,17 @@ public class PublishDnsUpdatesActionTest { private final DnsQueue dnsQueue = mock(DnsQueue.class); private final CloudTasksHelper cloudTasksHelper = new CloudTasksHelper(); private PublishDnsUpdatesAction action; + private InternetAddress outgoingRegistry; + private Lazy registrySupportEmail; + private Lazy registryCcEmail; private final SendEmailService emailService = mock(SendEmailService.class); - private SendEmailUtils sendEmailUtils; @BeforeEach void beforeEach() throws Exception { - sendEmailUtils = - new SendEmailUtils( - new InternetAddress("outgoing@registry.example"), - "UnitTest Registry", - ImmutableList.of("notification@test.example", "notification2@test.example"), - emailService); - createTld("xn--q9jyb4c"); + outgoingRegistry = new InternetAddress("outgoing@registry.example"); + registrySupportEmail = Lazies.of(new InternetAddress("registry@test.com")); + registryCcEmail = Lazies.of(new InternetAddress("registry-cc@test.com")); persistResource( Registry.get("xn--q9jyb4c") .asBuilder() @@ -143,6 +141,7 @@ public class PublishDnsUpdatesActionTest { int lockIndex, int numPublishLocks, LockHandler lockHandler) { + return new PublishDnsUpdatesAction( dnsWriterString, clock.nowUtc().minusHours(1), @@ -155,8 +154,10 @@ public class PublishDnsUpdatesActionTest { Duration.standardSeconds(10), "Subj", "Body %1$s %2$s %3$s %4$s %5$s", - "registry@test.com", "awesomeRegistry", + registrySupportEmail, + registryCcEmail, + outgoingRegistry, Optional.ofNullable(retryCount), Optional.empty(), dnsQueue, @@ -165,7 +166,7 @@ public class PublishDnsUpdatesActionTest { lockHandler, clock, cloudTasksHelper.getTestCloudTasksUtils(), - sendEmailUtils, + emailService, response); } @@ -413,7 +414,9 @@ public class PublishDnsUpdatesActionTest { assertThat(emailMessage.subject()).isEqualTo("Subj"); assertThat(emailMessage.body()) .isEqualTo( - "Body The Registrar example.xn--q9jyb4c domain awesomeRegistry registry@test.com"); + "Body The Registrar example.xn--q9jyb4c domain registry@test.com awesomeRegistry"); + assertThat(emailMessage.bccs().stream().findFirst().get().toString()) + .isEqualTo("registry-cc@test.com"); } @Test @@ -429,7 +432,9 @@ public class PublishDnsUpdatesActionTest { assertThat(emailMessage.subject()).isEqualTo("Subj"); assertThat(emailMessage.body()) .isEqualTo( - "Body The Registrar ns1.example.xn--q9jyb4c host awesomeRegistry registry@test.com"); + "Body The Registrar ns1.example.xn--q9jyb4c host registry@test.com awesomeRegistry"); + assertThat(emailMessage.bccs().stream().findFirst().get().toString()) + .isEqualTo("registry-cc@test.com"); } @Test