Spring Boot Email Sending in Practice: SMTP Configuration, Async Delivery, and Templated Emails

This article focuses on building an email delivery system quickly with Spring Boot. It addresses common pain points such as tedious notification email development, error-prone SMTP configuration, and limited template extensibility. It covers plain text emails, HTML emails, attachment emails, and asynchronous delivery. Keywords: Spring Boot, SMTP, email automation.

The technical specification snapshot outlines the implementation baseline

Parameter Description
Core Language Java 8+
Application Framework Spring Boot
Mail Protocol SMTP + STARTTLS
Build Tool Maven
Core Dependencies spring-boot-starter-mail, spring-boot-starter-web, spring-boot-starter-freemarker
Reference Platform QQ Mail SMTP
Original Popularity 394 views, 9 likes, 4 bookmarks

This solution is well suited for notification and user outreach responsibilities in applications

Spring Boot provides a solid abstraction over JavaMail. Developers only need to add the starter dependency and configure SMTP parameters to gain email sending capabilities. Compared with manually handling low-level protocol interactions, this approach fits rapid integration in business systems much better.

Typical scenarios include welcome emails for registration, order notifications, exception alerts, marketing outreach, and approval reminders. The core value is not simply “sending emails,” but consolidating message delivery across multiple business domains behind a unified service, which reduces long-term maintenance costs.

The minimum dependency set enables email capabilities immediately


<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>
    </dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
</dependencies>

This configuration adds a web testing entry point and the core Spring Mail capabilities.

Mail server configuration determines whether the system can connect to SMTP services reliably

Before sending email, you must enable SMTP in the mailbox provider’s console and obtain an authorization code. In this context, password is typically not the mailbox login password. It is usually an authorization credential specifically issued for third-party clients.

If you use QQ Mail, the common host is smtp.qq.com, the typical port is 587, and TLS is recommended. In production, you should place sensitive configuration in environment variables or a centralized configuration service instead of hardcoding it into the repository.

spring:
  mail:
    host: smtp.qq.com
    port: 587
    username: [email protected]
    password: your_authorization_code  # Authorization code, not the login password
    properties:
      mail:
        smtp:
          auth: true                   # Enable SMTP authentication
          starttls:
            enable: true               # Enable TLS encryption
            required: true             # Enforce TLS

This configuration defines the foundation for SMTP connectivity, authentication, and transport encryption.

The mail service class should provide a unified sending entry point instead of scattering logic across business code

It is best practice to centralize sending logic in MailService. This offers two major benefits: first, it simplifies unified exception handling and logging; second, it minimizes future changes when you switch template engines, add retry mechanisms, or integrate a message queue.

Plain text email is the simplest and most reliable implementation

@Service
public class MailService {

    @Autowired
    private JavaMailSender javaMailSender;

    @Value("${spring.mail.username}")
    private String from;

    public void sendSimpleMail(String to, String subject, String content) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(from);          // Set sender
        message.setTo(to);              // Set recipient
        message.setSubject(subject);    // Set subject
        message.setText(content);       // Set body
        javaMailSender.send(message);   // Send the email
    }
}

This code encapsulates the minimum viable flow for sending plain text email.

Rich text, attachments, and inline images cover most business notification needs

When an email needs brand styling, buttons, tables, or emphasized content, you should use HTML email. If you need to send invoices, reports, or contracts, you should add attachment support. Inline images work well for logos, banners, and status illustrations.

HTML email is better suited for operational notifications and formatted content

public void sendHtmlMail(String to, String subject, String htmlContent) {
    try {
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
        helper.setFrom(from);                  // Sender
        helper.setTo(to);                      // Recipient
        helper.setSubject(subject);            // Email subject
        helper.setText(htmlContent, true);     // true indicates HTML content
        javaMailSender.send(message);          // Send the email
    } catch (MessagingException e) {
        throw new RuntimeException("Failed to send HTML email", e);
    }
}

This code sends HTML email with renderable styles.

Attachment email is ideal for reports, documents, and offline materials

public void sendAttachmentsMail(String to, String subject, String content, String filePath) {
    try {
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
        helper.setFrom(from);                              // Sender
        helper.setTo(to);                                  // Recipient
        helper.setSubject(subject);                        // Email subject
        helper.setText(content);                           // Text content

        FileSystemResource file = new FileSystemResource(new File(filePath));
        helper.addAttachment(file.getFilename(), file);    // Add attachment
        javaMailSender.send(message);                      // Send the email
    } catch (MessagingException e) {
        throw new RuntimeException("Failed to send email with attachment", e);
    }
}

This code implements email sending with a local file attachment.

Asynchronous sending can significantly improve API response time

Email delivery depends on external SMTP services. Network fluctuations and server-side response latency can increase request time noticeably. If you send email synchronously in registration, ordering, or alerting APIs, it can slow down the main transaction path.

Spring Boot can move the sending action to a thread pool through @EnableAsync and @Async. A more advanced optimization is to write email requests into a message queue, which enables traffic smoothing, retries, and failure compensation.

@SpringBootApplication
@EnableAsync
public class MailApplication {
    public static void main(String[] args) {
        SpringApplication.run(MailApplication.class, args);
    }
}

@Async
public void sendSimpleMail(String to, String subject, String content) {
    // Send email asynchronously to avoid blocking the main thread
    sendSimpleMail(to, subject, content);
}

This example illustrates the asynchronous design idea. In a real project, you should avoid recursive self-invocation caused by using the same method name. It is better to split the async logic into a separate method.

Template engines make dynamic email content maintainable

Scenarios such as welcome emails, verification code notifications, and order status updates all require dynamic variables. If you concatenate HTML directly in Java strings, readability and maintainability degrade quickly.

FreeMarker is a common choice. Place template files in the resources/templates directory, populate variables through a model, render the final HTML, and then pass it to MimeMessageHelper for delivery. This approach creates a cleaner boundary between frontend styling and backend logic.

public void sendTemplateMail(String to, String subject, String templateName, Map<String, Object> model) {
    try {
        Template template = freemarkerConfiguration.getTemplate(templateName);
        String htmlContent = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);

        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
        helper.setFrom(from);                  // Sender
        helper.setTo(to);                      // Recipient
        helper.setSubject(subject);            // Subject
        helper.setText(htmlContent, true);     // Rendered HTML from the template
        javaMailSender.send(message);          // Send
    } catch (Exception e) {
        throw new RuntimeException("Failed to send template email", e);
    }
}

This code completes the full loop of template loading, variable rendering, and HTML email delivery.

Common failures usually fall into authentication, network, and encoding categories

Authorization failures are usually caused by an incorrect authorization code, SMTP not being enabled, or a mismatch in sender configuration. Connection timeouts are commonly related to the host, port, firewall rules, or outbound network restrictions on cloud servers. Garbled Chinese characters are usually caused by inconsistent email encoding settings rather than using UTF-8 throughout.

You should add send logs, exception categorization, timeout settings, and retry strategies in the service. If the system handles high-value notification flows, you should also introduce monitoring metrics such as success rate, average latency, and failure cause distribution.

The FAQ section answers the most common implementation questions

Q1: Why does it still show Authentication failed even when the configuration looks correct?

A: First, verify that you are using an authorization code instead of the login password. Then confirm that SMTP is enabled in the mailbox provider console and make sure the sender address exactly matches spring.mail.username.

Q2: Why is asynchronous email sending recommended in Spring Boot?

A: SMTP is an external network call, and both latency and failure probability are higher than local logic. Asynchronous execution protects the latency of core business APIs and prevents flows such as registration or order placement from being slowed down by email delivery.

Q3: When should I choose plain text email, and when should I use HTML or template-based email?

A: Use plain text email first for simple notifications such as alerts and verification codes. Choose HTML when you need brand styling, tables, or buttons. Choose template-based email when the content contains many dynamic variables and requires long-term maintainability.

Core Summary: This article systematically rebuilds a Spring Boot email delivery solution, covering SMTP configuration, plain text/HTML/attachment/inline image email implementation, as well as asynchronous delivery and FreeMarker template integration. It helps developers quickly build stable and extensible email automation capabilities.