Skip to content

Commit d7a63f0

Browse files
Add option to configure sourceArn for SES integration (#762)
AWS Java SDK v2 SES API ensures the necessary methods to setup sourceArn property at message sending moment but this configuration is not yet available via properties. Co-authored-by: Maciej Walkowiak <[email protected]>
1 parent c752dd1 commit d7a63f0

File tree

8 files changed

+54
-10
lines changed

8 files changed

+54
-10
lines changed

docs/src/main/asciidoc/_configprops.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
|spring.cloud.aws.ses.enabled | `+++true+++` | Enables Simple Email Service integration.
5858
|spring.cloud.aws.ses.endpoint | | Overrides the default endpoint.
5959
|spring.cloud.aws.ses.region | | Overrides the default region.
60+
|spring.cloud.aws.ses.source-arn | | Configures source ARN. Used only for sending authorization.
6061
|spring.cloud.aws.sns.enabled | `+++true+++` | Enables SNS integration.
6162
|spring.cloud.aws.sns.endpoint | | Overrides the default endpoint.
6263
|spring.cloud.aws.sns.region | | Overrides the default region.

docs/src/main/asciidoc/ses.adoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ The Spring Boot Starter for SES provides the following configuration options:
132132
| `spring.cloud.aws.ses.enabled` | Enables the SES integration. | No | `true`
133133
| `spring.cloud.aws.ses.endpoint` | Configures endpoint used by `SesClient`. | No |
134134
| `spring.cloud.aws.ses.region` | Configures region used by `SesClient`. | No |
135+
| `spring.cloud.aws.ses.sourceArn` | Configures source ARN, used only for sending authorization. | No |
135136
|===
136137

137138
Amazon SES is not available in all https://docs.aws.amazon.com/ses/latest/DeveloperGuide/regions.html[regions] of the
@@ -140,9 +141,13 @@ service will produce an error while using the mail service. Therefore, the regio
140141
sender configuration. The example below shows a typical combination of a region (`EU-CENTRAL-1`) that does not provide
141142
an SES service where the client is overridden to use a valid region (`EU-WEST-1`).
142143

144+
`sourceArn` is the ARN of the identity that is associated with the sending authorization policy. For information about when to use this parameter, see the
145+
description see https://docs.aws.amazon.com/ses/latest/dg/sending-authorization-delegate-sender-tasks-email.html[Amazon SES Developer Guide].
146+
143147
[source,properties,indent=0]
144148
----
145149
spring.cloud.aws.ses.region=eu-west-1
150+
spring.cloud.aws.ses.sourceArn=arn:aws:ses:eu-west-1:123456789012:identity/example.com
146151
----
147152

148153
=== IAM Permissions

spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/ses/SesAutoConfiguration.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,14 @@ public SesClient sesClient(SesProperties properties, AwsClientBuilderConfigurer
6161

6262
@Bean
6363
@ConditionalOnMissingClass("jakarta.mail.Session")
64-
public MailSender simpleMailSender(SesClient sesClient) {
65-
return new SimpleEmailServiceMailSender(sesClient);
64+
public MailSender simpleMailSender(SesClient sesClient, SesProperties properties) {
65+
return new SimpleEmailServiceMailSender(sesClient, properties.getSourceArn());
6666
}
6767

6868
@Bean
6969
@ConditionalOnClass(name = "jakarta.mail.Session")
70-
public JavaMailSender javaMailSender(SesClient sesClient) {
71-
return new SimpleEmailServiceJavaMailSender(sesClient);
70+
public JavaMailSender javaMailSender(SesClient sesClient, SesProperties properties) {
71+
return new SimpleEmailServiceJavaMailSender(sesClient, properties.getSourceArn());
7272
}
7373

7474
}

spring-cloud-aws-autoconfigure/src/main/java/io/awspring/cloud/autoconfigure/ses/SesProperties.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import io.awspring.cloud.autoconfigure.AwsClientProperties;
1919
import org.springframework.boot.context.properties.ConfigurationProperties;
20+
import org.springframework.lang.Nullable;
2021

2122
/**
2223
* Properties related to AWS Simple Email Service.
@@ -32,4 +33,18 @@ public class SesProperties extends AwsClientProperties {
3233
*/
3334
public static final String PREFIX = "spring.cloud.aws.ses";
3435

36+
/**
37+
* Configures source ARN. Used only for sending authorization.
38+
*/
39+
@Nullable
40+
private String sourceArn;
41+
42+
@Nullable
43+
public String getSourceArn() {
44+
return sourceArn;
45+
}
46+
47+
public void setSourceArn(@Nullable String sourceArn) {
48+
this.sourceArn = sourceArn;
49+
}
3550
}

spring-cloud-aws-ses/src/main/java/io/awspring/cloud/ses/SimpleEmailServiceJavaMailSender.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,11 @@ public class SimpleEmailServiceJavaMailSender extends SimpleEmailServiceMailSend
7575
private FileTypeMap defaultFileTypeMap;
7676

7777
public SimpleEmailServiceJavaMailSender(SesClient sesClient) {
78-
super(sesClient);
78+
this(sesClient, null);
79+
}
80+
81+
public SimpleEmailServiceJavaMailSender(SesClient sesClient, @Nullable String sourceArn) {
82+
super(sesClient, sourceArn);
7983
}
8084

8185
/**
@@ -202,8 +206,8 @@ public void send(MimeMessage... mimeMessages) throws MailException {
202206
try {
203207
RawMessage rawMessage = createRawMessage(mimeMessage);
204208

205-
SendRawEmailResponse sendRawEmailResponse = getEmailService()
206-
.sendRawEmail(SendRawEmailRequest.builder().rawMessage(rawMessage).build());
209+
SendRawEmailResponse sendRawEmailResponse = getEmailService().sendRawEmail(
210+
SendRawEmailRequest.builder().sourceArn(getSourceArn()).rawMessage(rawMessage).build());
207211

208212
if (LOGGER.isDebugEnabled()) {
209213
LOGGER.debug("Message with id: {} successfully sent", sendRawEmailResponse.messageId());

spring-cloud-aws-ses/src/main/java/io/awspring/cloud/ses/SimpleEmailServiceMailSender.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.slf4j.Logger;
2121
import org.slf4j.LoggerFactory;
2222
import org.springframework.beans.factory.DisposableBean;
23+
import org.springframework.lang.Nullable;
2324
import org.springframework.mail.MailException;
2425
import org.springframework.mail.MailSendException;
2526
import org.springframework.mail.MailSender;
@@ -50,8 +51,16 @@ public class SimpleEmailServiceMailSender implements MailSender, DisposableBean
5051

5152
private final SesClient sesClient;
5253

54+
@Nullable
55+
private final String sourceArn;
56+
5357
public SimpleEmailServiceMailSender(SesClient sesClient) {
58+
this(sesClient, null);
59+
}
60+
61+
public SimpleEmailServiceMailSender(SesClient sesClient, @Nullable String sourceArn) {
5462
this.sesClient = sesClient;
63+
this.sourceArn = sourceArn;
5564
}
5665

5766
@Override
@@ -94,6 +103,11 @@ protected SesClient getEmailService() {
94103
return this.sesClient;
95104
}
96105

106+
@Nullable
107+
protected String getSourceArn() {
108+
return sourceArn;
109+
}
110+
97111
private SendEmailRequest prepareMessage(SimpleMailMessage simpleMailMessage) {
98112
Assert.notNull(simpleMailMessage, "simpleMailMessage are required");
99113
Destination.Builder destinationBuilder = Destination.builder();
@@ -112,7 +126,8 @@ private SendEmailRequest prepareMessage(SimpleMailMessage simpleMailMessage) {
112126
Message message = Message.builder().body(body).subject(subject).build();
113127

114128
SendEmailRequest.Builder emailRequestBuilder = SendEmailRequest.builder()
115-
.destination(destinationBuilder.build()).source(simpleMailMessage.getFrom()).message(message);
129+
.destination(destinationBuilder.build()).source(simpleMailMessage.getFrom()).sourceArn(getSourceArn())
130+
.message(message);
116131

117132
if (StringUtils.hasText(simpleMailMessage.getReplyTo())) {
118133
emailRequestBuilder.replyToAddresses(simpleMailMessage.getReplyTo());

spring-cloud-aws-ses/src/test/java/io/awspring/cloud/ses/SimpleEmailServiceJavaMailSenderTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@ void testCreateMimeMessageFromPreDefinedMessage() throws Exception {
149149
void testSendMimeMessage() throws MessagingException {
150150
SesClient emailService = mock(SesClient.class);
151151

152-
JavaMailSender mailSender = new SimpleEmailServiceJavaMailSender(emailService);
152+
JavaMailSender mailSender = new SimpleEmailServiceJavaMailSender(emailService,
153+
"arn:aws:ses:us-east-1:00000001:identity/domain.com");
153154

154155
ArgumentCaptor<SendRawEmailRequest> request = ArgumentCaptor.forClass(SendRawEmailRequest.class);
155156
when(emailService.sendRawEmail(request.capture()))
@@ -158,6 +159,7 @@ void testSendMimeMessage() throws MessagingException {
158159
MimeMessage mimeMessage = createMimeMessage();
159160
mailSender.send(mimeMessage);
160161
assertThat(mimeMessage.getMessageID()).isEqualTo("123");
162+
assertThat(request.getValue().sourceArn()).isEqualTo("arn:aws:ses:us-east-1:00000001:identity/domain.com");
161163
}
162164

163165
@Test

spring-cloud-aws-ses/src/test/java/io/awspring/cloud/ses/SimpleEmailServiceMailSenderTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ class SimpleEmailServiceMailSenderTest {
4545
@Test
4646
void testSendSimpleMailWithMinimalProperties() {
4747
SesClient emailService = mock(SesClient.class);
48-
SimpleEmailServiceMailSender mailSender = new SimpleEmailServiceMailSender(emailService);
48+
SimpleEmailServiceMailSender mailSender = new SimpleEmailServiceMailSender(emailService,
49+
"arn:aws:ses:us-east-1:00000000:identity/domain.com");
4950

5051
SimpleMailMessage simpleMailMessage = createSimpleMailMessage();
5152

@@ -63,6 +64,7 @@ void testSendSimpleMailWithMinimalProperties() {
6364
assertThat(sendEmailRequest.message().body().text().data()).isEqualTo(simpleMailMessage.getText());
6465
assertThat(sendEmailRequest.destination().ccAddresses().size()).isEqualTo(0);
6566
assertThat(sendEmailRequest.destination().bccAddresses().size()).isEqualTo(0);
67+
assertThat(sendEmailRequest.sourceArn()).isEqualTo("arn:aws:ses:us-east-1:00000000:identity/domain.com");
6668
}
6769

6870
@Test

0 commit comments

Comments
 (0)