This comprehensive guide will walk you through setting up Amazon SES (Simple Email Service) and integrating it with a Spring Boot 3 application.
Part 1: Amazon SES Setup
1.1 Create an AWS Account
If you don't have one already, sign up at AWS.
1.2 Access Amazon SES
- Log in to AWS Management Console
- Navigate to "Simple Email Service" (SES)
- Select your region (note: not all regions support SES)
1.3 Verify Email Addresses/Domains
For testing purposes, you'll need to verify at least one email address:
- Go to "Verified identities" in SES console
- Click "Create identity"
- Select "Email address" and enter your test email
- Click "Create identity"
- Check your email inbox for verification email and confirm
For production, you'll want to verify your domain instead.
1.4 Get AWS Credentials
- Go to IAM (Identity and Access Management)
- Create a new user with programmatic access
- Attach the "AmazonSESFullAccess" policy
- Note the Access Key ID and Secret Access Key (you'll need these for Spring Boot)
1.5 Move Out of Sandbox (Optional for Production)
By default, SES starts in sandbox mode with limitations:
- Can only send to verified addresses
- Limited sending quota
To request production access:
- In SES console, go to "Sending statistics"
- Click "Request a sending limit increase"
- Complete the form
Part 2: Spring Boot Application Setup
2.1 Create a New Spring Boot Project
Use Spring Initializr with:
- Project: Maven or Gradle
- Language: Java
- Spring Boot: 3.x
- Dependencies: Spring Web, Lombok
2.2 Add AWS SDK Dependency
Add to your pom.xml
(Maven):
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>ses</artifactId>
<version>2.20.0</version>
</dependency>
Or for Gradle (build.gradle
):
implementation 'software.amazon.awssdk:ses:2.20.0'
2.3 Configure AWS Credentials
Add to application.properties
or application.yml
:
# AWS Configuration
aws.access-key-id=YOUR_ACCESS_KEY
aws.secret-key=YOUR_SECRET_KEY
aws.region=us-east-1 # Change to your SES region
# Email Configuration
aws.ses.sender=verified-email@example.com
2.4 Create Configuration Class
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ses.SesClient;
@Configuration
public class AwsSesConfig {
@Value("${aws.access-key-id}")
private String accessKey;
@Value("${aws.secret-key}")
private String secretKey;
@Value("${aws.region}")
private String region;
@Bean
public SesClient sesClient() {
AwsBasicCredentials awsCreds = AwsBasicCredentials.create(accessKey, secretKey);
return SesClient.builder()
.region(Region.of(region))
.credentialsProvider(StaticCredentialsProvider.create(awsCreds))
.build();
}
}
2.5 Create Email Service
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import software.amazon.awssdk.services.ses.SesClient;
import software.amazon.awssdk.services.ses.model.*;
@Service
@RequiredArgsConstructor
public class EmailService {
private final SesClient sesClient;
@Value("${aws.ses.sender}")
private String senderEmail;
public void sendEmail(String to, String subject, String body) {
try {
SendEmailRequest request = SendEmailRequest.builder()
.destination(Destination.builder().toAddresses(to).build())
.message(Message.builder()
.subject(Content.builder().data(subject).build())
.body(Body.builder()
.html(Content.builder().data(body).build())
.build())
.build())
.source(senderEmail)
.build();
sesClient.sendEmail(request);
System.out.println("Email sent successfully to " + to);
} catch (SesException e) {
System.err.println("Error sending email: " + e.awsErrorDetails().errorMessage());
throw e;
}
}
}
2.6 Create REST Controller
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/email")
@RequiredArgsConstructor
public class EmailController {
private final EmailService emailService;
@PostMapping("/send")
public String sendEmail(@RequestBody EmailRequest request) {
emailService.sendEmail(request.getTo(), request.getSubject(), request.getBody());
return "Email sent successfully!";
}
}
// DTO for request
record EmailRequest(String to, String subject, String body) {}
Part 3: Testing with Postman
3.1 Start Your Spring Boot Application
Run your application and note the port (default is 8080).
3.2 Create Postman Request
- Open Postman
- Create a new POST request to:
http://localhost:8080/api/email/send
- Set Headers:
Content-Type: application/json
- Set Body (raw, JSON):
{
"to": "recipient@example.com", // Use verified email
"subject": "Test Email from Spring Boot",
"body": "<h1>Hello from Spring Boot!</h1><p>This is a test email sent via Amazon SES.</p>"
}
3.3 Send the Request
Click "Send" and you should receive:
- 200 OK response with success message
- Email in your inbox (check spam folder if not received)
Part 4: Advanced Features
4.1 HTML Templates with Thymeleaf
Add Thymeleaf dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Create template in src/main/resources/templates/email-template.html
:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title th:remove="all">Template for HTML email</title>
</head>
<body>
<h1 th:text="${subject}">Default Subject</h1>
<p th:text="${message}">Default message</p>
<footer>
<p>Best regards,<br>The Team</p>
</footer>
</body>
</html>
Update EmailService:
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
@Service
@RequiredArgsConstructor
public class EmailService {
private final TemplateEngine templateEngine;
// ... existing code ...
public void sendTemplateEmail(String to, String subject, String message) {
Context context = new Context();
context.setVariable("subject", subject);
context.setVariable("message", message);
String body = templateEngine.process("email-template", context);
sendEmail(to, subject, body);
}
}
4.2 Attachments
To add attachments, you'll need to use the AWS SDK's SendRawEmail
API.
4.3 Error Handling
Enhance your error handling with custom exceptions and proper HTTP responses.
Part 5: Production Considerations
- Domain Verification: Verify your domain instead of individual emails
- DKIM Signing: Set up DKIM for better email deliverability
- Sending Limits: Monitor and request increases as needed
- Bounce/Complaint Handling: Set up SNS notifications for bounces/complaints
- Monitoring: Use CloudWatch to monitor your SES metrics
Troubleshooting
- Emails not received:
- Check spam folder
- Verify sender/recipient emails are verified
- Check SES sending statistics for errors
- Authentication errors:
- Double-check AWS credentials
- Verify IAM permissions
- Ensure region matches SES region
- Rate limiting:
- Check your SES quotas
- Implement retry logic in your code
This complete guide should help you set up email sending with Spring Boot 3 and Amazon SES from scratch to production-ready implementation.