1
0
mirror of https://github.com/google/nomulus synced 2026-05-20 23:01:53 +00:00

Verify user can send email (#3045)

Change the CannedScriptExecutionAction to send a email
message as a user-specified G workspace user.

This change is part of b/510340944, to verify that a newly
added dedicated sender is properly set up for sending emails.

Once the new sender is tested, the changes in this PR can be
dropped.
This commit is contained in:
Weimin Yu
2026-05-14 11:13:57 -04:00
committed by GitHub
parent 56fe588b56
commit d9d83205c7
4 changed files with 177 additions and 34 deletions

View File

@@ -54,9 +54,15 @@ public class BatchModule {
static final int DEFAULT_MAX_QPS = 10;
@Provides
@Parameter("url")
static String provideUrl(HttpServletRequest req) {
return extractRequiredParameter(req, "url");
@Parameter("sender")
static String provideSender(HttpServletRequest req) {
return extractRequiredParameter(req, "sender");
}
@Provides
@Parameter("receiver")
static String provideReceiver(HttpServletRequest req) {
return extractRequiredParameter(req, "receiver");
}
@Provides

View File

@@ -16,30 +16,32 @@ package google.registry.batch;
import static google.registry.request.Action.Method.GET;
import static google.registry.request.Action.Method.POST;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.api.services.gmail.Gmail;
import com.google.common.flogger.FluentLogger;
import dagger.Lazy;
import google.registry.config.RegistryConfig.Config;
import google.registry.groups.GmailClient;
import google.registry.request.Action;
import google.registry.request.Parameter;
import google.registry.request.Response;
import google.registry.request.UrlConnectionService;
import google.registry.request.UrlConnectionUtils;
import google.registry.request.auth.Auth;
import google.registry.util.EmailMessage;
import google.registry.util.Retrier;
import jakarta.inject.Inject;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import jakarta.mail.internet.AddressException;
import jakarta.mail.internet.InternetAddress;
/**
* Action that executes a canned script specified by the caller.
*
* <p>This class provides a hook for invoking hard-coded methods. The main use case is to verify in
* Sandbox and Production environments new features that depend on environment-specific
* configurations. For example, the {@code DelegatedCredential}, which requires correct GWorkspace
* configuration, has been tested this way. Since it is a hassle to add or remove endpoints, we keep
* this class all the time.
* configurations.
*
* <p>This action can be invoked using the Nomulus CLI command: {@code nomulus -e ${env} curl
* --service BACKEND -X POST -u '/_dr/task/executeCannedScript}'}
* --service BACKEND -X POST -d 'sender=sender@example.com' -d 'receiver=receiver@example.com' -u
* '/_dr/task/executeCannedScript'}
*/
@Action(
service = Action.Service.BACKEND,
@@ -50,39 +52,50 @@ import javax.net.ssl.HttpsURLConnection;
public class CannedScriptExecutionAction implements Runnable {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@Inject UrlConnectionService urlConnectionService;
@Inject Lazy<Gmail> gmail;
@Inject Retrier retrier;
@Inject
@Config("isEmailSendingEnabled")
boolean isEmailSendingEnabled;
@Inject Response response;
@Inject
@Parameter("url")
String url;
@Parameter("sender")
String sender;
@Inject
@Parameter("receiver")
String receiver;
@Inject
CannedScriptExecutionAction() {}
@Override
public void run() {
Integer responseCode = null;
String responseContent = null;
// For b/510340944, validating a new G Workspace user can send email. Code below can be
// removed or changed afterward.
try {
logger.atInfo().log("Connecting to: %s", url);
HttpsURLConnection connection =
(HttpsURLConnection) urlConnectionService.createConnection(new URL(url));
responseCode = connection.getResponseCode();
logger.atInfo().log("Code: %d", responseCode);
logger.atInfo().log("Headers: %s", connection.getHeaderFields());
responseContent = new String(UrlConnectionUtils.getResponseBytes(connection), UTF_8);
logger.atInfo().log("Response: %s", responseContent);
logger.atInfo().log("Sending email from %s to %s", sender, receiver);
GmailClient gmailClient =
new GmailClient(
gmail, retrier, isEmailSendingEnabled, sender, sender, new InternetAddress(sender));
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))
.build());
response.setPayload("Email sent successfully.");
} catch (AddressException e) {
logger.atWarning().withCause(e).log(
"Invalid email address: sender=%s, receiver=%s", sender, receiver);
response.setStatus(400);
response.setPayload("Invalid email address provided.");
} catch (Exception e) {
logger.atWarning().withCause(e).log("Connection to %s failed", url);
logger.atSevere().withCause(e).log("Failed to send email");
throw new RuntimeException(e);
} finally {
if (responseCode != null) {
response.setStatus(responseCode);
}
if (responseContent != null) {
response.setPayload(responseContent);
}
}
}
}

View File

@@ -56,8 +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
@Inject
GmailClient(
public GmailClient(
Lazy<Gmail> gmail,
Retrier retrier,
@Config("isEmailSendingEnabled") boolean isEmailSendingEnabled,