From 3894ca6971e4fcb9829d631fe8ed524151d46aec Mon Sep 17 00:00:00 2001 From: Weimin Yu Date: Tue, 19 May 2026 17:02:01 -0400 Subject: [PATCH] More debugging code for replyTo address (#3053) The replyTo header works in manual tests. Add code emulating BillingEmailUtils behavior and see if that causes the problem. Also experimenting not to set the From header in GmaiClient, since whatever we set is overridden anyway. --- .../google/registry/batch/BatchModule.java | 6 +-- .../batch/CannedScriptExecutionAction.java | 40 ++++++++++++++----- .../google/registry/groups/GmailClient.java | 22 ++++++++-- 3 files changed, 53 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/google/registry/batch/BatchModule.java b/core/src/main/java/google/registry/batch/BatchModule.java index b2854c2fa..047377752 100644 --- a/core/src/main/java/google/registry/batch/BatchModule.java +++ b/core/src/main/java/google/registry/batch/BatchModule.java @@ -54,9 +54,9 @@ public class BatchModule { static final int DEFAULT_MAX_QPS = 10; @Provides - @Parameter("sender") - static String provideSender(HttpServletRequest req) { - return extractRequiredParameter(req, "sender"); + @Parameter("replyTo") + static String provideReplyTo(HttpServletRequest req) { + return extractRequiredParameter(req, "replyTo"); } @Provides diff --git a/core/src/main/java/google/registry/batch/CannedScriptExecutionAction.java b/core/src/main/java/google/registry/batch/CannedScriptExecutionAction.java index a83e48997..7ea738723 100644 --- a/core/src/main/java/google/registry/batch/CannedScriptExecutionAction.java +++ b/core/src/main/java/google/registry/batch/CannedScriptExecutionAction.java @@ -18,7 +18,9 @@ import static google.registry.request.Action.Method.GET; import static google.registry.request.Action.Method.POST; import com.google.api.services.gmail.Gmail; +import com.google.common.collect.ImmutableList; import com.google.common.flogger.FluentLogger; +import com.google.common.net.MediaType; import dagger.Lazy; import google.registry.config.RegistryConfig.Config; import google.registry.groups.GmailClient; @@ -31,6 +33,7 @@ import google.registry.util.Retrier; import jakarta.inject.Inject; import jakarta.mail.internet.AddressException; import jakarta.mail.internet.InternetAddress; +import java.util.Optional; /** * Action that executes a canned script specified by the caller. @@ -62,13 +65,16 @@ public class CannedScriptExecutionAction implements Runnable { @Inject Response response; @Inject - @Parameter("sender") - String sender; + @Parameter("replyTo") + String replyTo; @Inject @Parameter("receiver") String receiver; + @Config("invoiceReplyToEmailAddress") + Optional replyToEmailAddressFromConfig; + @Inject CannedScriptExecutionAction() {} @@ -77,20 +83,36 @@ public class CannedScriptExecutionAction implements Runnable { // For b/510340944, validating a new G Workspace user can send email. Code below can be // removed or changed afterward. try { - logger.atInfo().log("Sending email from %s to %s", sender, receiver); + logger.atInfo().log("Sending email to %s with replyTo %s", receiver, replyTo); GmailClient gmailClient = - new GmailClient( - gmail, retrier, isEmailSendingEnabled, sender, sender, new InternetAddress(sender)); + new GmailClient(gmail, retrier, isEmailSendingEnabled, new InternetAddress(replyTo)); gmailClient.sendEmail( EmailMessage.newBuilder() .addRecipient(new InternetAddress(receiver)) - .setSubject(String.format("Email send test from %s", sender)) - .setBody(String.format("This is a test email sent from %s to %s.", sender, receiver)) + .setSubject(String.format("Email with manually set replyTo header %s", replyTo)) + .setBody("See subject") .build()); - response.setPayload("Email sent successfully."); + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + gmailClient.sendEmail( + EmailMessage.newBuilder() + .setSubject( + String.format( + "Email with injected replyTo header %s", replyToEmailAddressFromConfig)) + .setBody("See header") + .setRecipients(ImmutableList.of(new InternetAddress(receiver))) + .setReplyToEmailAddress(replyToEmailAddressFromConfig) + .setContentType(MediaType.HTML_UTF_8) + .build()); + response.setPayload("Emails sent successfully."); } catch (AddressException e) { logger.atWarning().withCause(e).log( - "Invalid email address: sender=%s, receiver=%s", sender, receiver); + "Invalid email address: sender=%s, receiver=%s", replyTo, receiver); response.setStatus(400); response.setPayload("Invalid email address provided."); } catch (Exception e) { diff --git a/core/src/main/java/google/registry/groups/GmailClient.java b/core/src/main/java/google/registry/groups/GmailClient.java index 32245b0f0..d66ec18c7 100644 --- a/core/src/main/java/google/registry/groups/GmailClient.java +++ b/core/src/main/java/google/registry/groups/GmailClient.java @@ -56,9 +56,9 @@ public final class GmailClient { private final InternetAddress outgoingEmailAddressWithUsername; private final InternetAddress replyToEmailAddress; - // TODO(b/510340944): make package private after feature is rolled out + // TODO(b/510340944): drop sender info. Sender is determined by the Gmail credential owner. @Inject - public GmailClient( + GmailClient( Lazy gmail, Retrier retrier, @Config("isEmailSendingEnabled") boolean isEmailSendingEnabled, @@ -78,6 +78,20 @@ public final class GmailClient { } } + // TODO(b/510340944): Remove this experiment method + public GmailClient( + Lazy gmail, + Retrier retrier, + @Config("isEmailSendingEnabled") boolean isEmailSendingEnabled, + @Config("replyToEmailAddress") InternetAddress replyToEmailAddress) { + + this.gmail = gmail; + this.retrier = retrier; + this.isEmailSendingEnabled = isEmailSendingEnabled; + this.replyToEmailAddress = replyToEmailAddress; + this.outgoingEmailAddressWithUsername = null; + } + /** * Sends {@code emailMessage} using {@link Gmail}. */ @@ -117,7 +131,9 @@ public final class GmailClient { try { MimeMessage msg = new MimeMessage(Session.getDefaultInstance(new Properties(), /* authenticator= */ null)); - msg.setFrom(this.outgoingEmailAddressWithUsername); + if (this.outgoingEmailAddressWithUsername != null) { + msg.setFrom(this.outgoingEmailAddressWithUsername); + } msg.setReplyTo( new InternetAddress[] {emailMessage.replyToEmailAddress().orElse(replyToEmailAddress)}); msg.addRecipients(