spring-mail
Spring Mail for sending emails in Spring Boot 3.x. Covers JavaMailSender, SimpleMailMessage, MimeMessage, HTML emails, attachments, templates (Thymeleaf/FreeMarker), async sending, and testing. USE WHEN: user mentions "spring mail", "JavaMailSender", "email Spring Boot", "send email", "MimeMessage", "email templates", "SMTP Spring" DO NOT USE FOR: transactional email services (SendGrid, SES) - use their SDKs, SMS/push notifications - use appropriate services
What this skill does
# Spring Mail
## Quick Start
```yaml
# application.yml
spring:
mail:
host: smtp.gmail.com
port: 587
username: ${MAIL_USERNAME}
password: ${MAIL_PASSWORD}
properties:
mail:
smtp:
auth: true
starttls:
enable: true
```
```java
@Service
@RequiredArgsConstructor
public class EmailService {
private final JavaMailSender mailSender;
public void sendSimpleEmail(String to, String subject, String text) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(to);
message.setSubject(subject);
message.setText(text);
message.setFrom("[email protected]");
mailSender.send(message);
}
}
```
---
## Configuration
```java
@Configuration
public class MailConfig {
@Bean
public JavaMailSender javaMailSender(MailProperties props) {
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost(props.getHost());
mailSender.setPort(props.getPort());
mailSender.setUsername(props.getUsername());
mailSender.setPassword(props.getPassword());
Properties javaMailProperties = new Properties();
javaMailProperties.put("mail.smtp.auth", true);
javaMailProperties.put("mail.smtp.starttls.enable", true);
javaMailProperties.put("mail.smtp.connectiontimeout", 5000);
javaMailProperties.put("mail.smtp.timeout", 5000);
javaMailProperties.put("mail.smtp.writetimeout", 5000);
mailSender.setJavaMailProperties(javaMailProperties);
return mailSender;
}
}
```
---
## MimeMessage (HTML & Attachments)
```java
@Service
@RequiredArgsConstructor
@Slf4j
public class EmailService {
private final JavaMailSender mailSender;
// HTML Email
public void sendHtmlEmail(String to, String subject, String htmlContent)
throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
helper.setTo(to);
helper.setSubject(subject);
helper.setText(htmlContent, true); // true = HTML
helper.setFrom("[email protected]");
mailSender.send(message);
}
// Email con attachment
public void sendEmailWithAttachment(String to, String subject, String text,
String attachmentPath) throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(text);
helper.setFrom("[email protected]");
FileSystemResource file = new FileSystemResource(new File(attachmentPath));
helper.addAttachment(file.getFilename(), file);
mailSender.send(message);
}
// Email con inline image
public void sendEmailWithInlineImage(String to, String subject,
String htmlContent, String imagePath)
throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo(to);
helper.setSubject(subject);
// Reference: <img src="cid:logo">
helper.setText(htmlContent, true);
helper.setFrom("[email protected]");
FileSystemResource image = new FileSystemResource(new File(imagePath));
helper.addInline("logo", image);
mailSender.send(message);
}
// Multiple recipients
public void sendToMultiple(String[] to, String[] cc, String[] bcc,
String subject, String text) throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message);
helper.setTo(to);
if (cc != null) helper.setCc(cc);
if (bcc != null) helper.setBcc(bcc);
helper.setSubject(subject);
helper.setText(text);
helper.setFrom("[email protected]");
mailSender.send(message);
}
}
```
---
## Thymeleaf Templates
```java
@Service
@RequiredArgsConstructor
public class TemplateEmailService {
private final JavaMailSender mailSender;
private final TemplateEngine templateEngine;
public void sendWelcomeEmail(String to, String userName) throws MessagingException {
Context context = new Context();
context.setVariable("userName", userName);
context.setVariable("activationLink", "https://example.com/activate/123");
String htmlContent = templateEngine.process("email/welcome", context);
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
helper.setTo(to);
helper.setSubject("Welcome to Our Platform!");
helper.setText(htmlContent, true);
helper.setFrom("[email protected]");
mailSender.send(message);
}
public void sendOrderConfirmation(String to, Order order) throws MessagingException {
Context context = new Context();
context.setVariable("order", order);
context.setVariable("items", order.getItems());
context.setVariable("total", order.getTotal());
String htmlContent = templateEngine.process("email/order-confirmation", context);
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
helper.setTo(to);
helper.setSubject("Order Confirmation #" + order.getId());
helper.setText(htmlContent, true);
helper.setFrom("[email protected]");
mailSender.send(message);
}
}
```
```html
<!-- templates/email/welcome.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
</head>
<body style="font-family: Arial, sans-serif;">
<div style="max-width: 600px; margin: 0 auto; padding: 20px;">
<h1 style="color: #333;">Welcome, <span th:text="${userName}">User</span>!</h1>
<p>Thank you for joining our platform.</p>
<p>Please click the button below to activate your account:</p>
<a th:href="${activationLink}"
style="display: inline-block; padding: 10px 20px; background-color: #007bff;
color: white; text-decoration: none; border-radius: 5px;">
Activate Account
</a>
</div>
</body>
</html>
```
---
## Async Email Sending
```java
@Service
@RequiredArgsConstructor
@Slf4j
public class AsyncEmailService {
private final JavaMailSender mailSender;
private final TemplateEngine templateEngine;
@Async("emailExecutor")
public CompletableFuture<Void> sendEmailAsync(EmailRequest request) {
try {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
helper.setTo(request.getTo());
helper.setSubject(request.getSubject());
helper.setText(request.getContent(), request.isHtml());
helper.setFrom(request.getFrom());
mailSender.send(message);
log.info("Email sent successfully to: {}", request.getTo());
return CompletableFuture.completedFuture(null);
} catch (Exception e) {
log.error("Failed to send email to: {}", request.getTo(), e);
return CompletableFuture.failedFuture(e);
}
}
@Async("emailExecutor")
@Retryable(retryFor = MailException.class, maxAttempts = 3,
backoff = @Backoff(delay = 1000, multiplier = 2))
public void sendWithRetry(String to, String subject, String content) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(to);
Related in Web Dev
generating-lwc-components
IncludedLightning Web Components with PICKLES methodology and 165-point scoring. Use this skill when the user creates or edits LWC components, builds wire service patterns, or writes Jest tests for LWC. TRIGGER when: user creates/edits LWC components, touches lwc/**/*.js, .html, .css, .js-meta.xml files, or asks about wire service, SLDS, or Jest LWC tests. DO NOT TRIGGER when: Apex classes (use generating-apex), Aura components, or Visualforce.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Set up queries with useQuery, mutations with useMutation, configure QueryClient caching strategies, implement optimistic updates, and handle infinite scroll with useInfiniteQuery. Use when: setting up data fetching in React projects, migrating from v4 to v5, or fixing object syntax required errors, query callbacks removed issues, cacheTime renamed to gcTime, isPending vs isLoading confusion, keepPreviousData removed problems.
document-processor-api
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
nutrient-document-processing
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Covers useMutationState, simplified optimistic updates, throwOnError, network mode (offline/PWA), and infiniteQueryOptions. Use when setting up data fetching, fixing v4→v5 migration errors (object syntax, gcTime, isPending, keepPreviousData), or debugging SSR/hydration issues with streaming server components.
accelint-nextjs-best-practices
IncludedNext.js performance optimization and best practices. Use when writing Next.js code (App Router or Pages Router); implementing Server Components, Server Actions, or API routes; optimizing RSC serialization, data fetching, or server-side rendering; reviewing Next.js code for performance issues; fixing authentication in Server Actions; or implementing Suspense boundaries, parallel data fetching, or request deduplication.