Welcome emails upon user registration and sending password reset links are features you’ll encounter in virtually every real-world project. Spring Boot provides a convenient starter called spring-boot-starter-mail, and with JavaMailSender you can implement email sending with minimal effort.

This article walks through everything you need in practice: adding the dependency, configuring Gmail SMTP, sending plain text and HTML emails, and making it asynchronous with @Async.

Adding spring-boot-starter-mail

Start by adding the dependency.

Maven:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

Gradle:

implementation 'org.springframework.boot:spring-boot-starter-mail'

This alone auto-registers a JavaMailSenderImpl Bean. All that’s left is configuring the connection.

Configuring Gmail SMTP in application.properties

spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username[email protected]
spring.mail.password=${MAIL_PASSWORD}
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true

Port 587 (STARTTLS) is the standard choice. If you use port 465 (SSL), specify mail.smtp.ssl.enable=true instead of starttls.enable.

Avoid hardcoding the password — reference it via the environment variable ${MAIL_PASSWORD}. For more on managing configuration files, see the application.properties configuration guide and switching environment-specific settings with profiles.

Generating a Gmail App Password

If you have two-factor authentication enabled on Gmail (essentially required for modern accounts), standard password-based SMTP authentication will fail. You need to generate an App Password.

Here are the steps:

  1. Open the “Security” page of your Google Account
  2. Select “2-Step Verification”
  3. Scroll down and select “App passwords”
  4. Enter an app name and click “Create”
  5. Set the displayed 16-character password as the MAIL_PASSWORD environment variable

Avoid writing this password directly in application.properties — there’s a risk of accidentally committing it to Git.

Sending a Plain Text Email (Minimal Working Example)

Using SimpleMailMessage, you can send an email in just a few lines.

@Service
public class EmailService {

    private final JavaMailSender mailSender;

    public EmailService(JavaMailSender mailSender) {
        this.mailSender = mailSender;
    }

    public void sendWelcomeEmail(String to, String username) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom("[email protected]");
        message.setTo(to);
        message.setSubject("ご登録ありがとうございます");
        message.setText("こんにちは、" + username + "さん!\nご登録いただきありがとうございます。");
        mailSender.send(message);
    }
}

Inject JavaMailSender via constructor injection and call send() — it’s that simple.

Sending HTML Emails (MimeMessage)

To send HTML emails, use MimeMessage and MimeMessageHelper.

public void sendHtmlEmail(String to, String subject, String htmlContent)
        throws MessagingException {
    MimeMessage message = mailSender.createMimeMessage();
    MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
    helper.setFrom("[email protected]");
    helper.setTo(to);
    helper.setSubject(subject);
    helper.setText(htmlContent, true); // true treats content as HTML
    mailSender.send(message);
}

The key is passing true as the second argument to helper.setText(). Explicitly specifying UTF-8 as the character encoding prevents garbled text.

It’s recommended to write HTML styles as inline CSS, since some email clients ignore references to external CSS files. You can also manage HTML templates with Thymeleaf, but that’s a topic for another time.

Sending Attachments

Use MimeMessageHelper.addAttachment() to attach files.

helper.addAttachment("invoice.pdf", new FileSystemResource("/path/to/invoice.pdf"));

To attach from a byte array, pass a ByteArrayResource. Be mindful of timeouts and mail server size limits when attaching large files.

Asynchronous Sending with @Async

Communicating with an SMTP server takes time, so synchronous execution on the request thread will slow down your responses. Use @Async to make it asynchronous.

First, add @EnableAsync to a configuration class.

@Configuration
@EnableAsync
public class AsyncConfig {
}

Simply annotate the send method with @Async to make it asynchronous.

@Async
public void sendWelcomeEmailAsync(String to, String username) {
    // Same logic as sendWelcomeEmail
}

One important caveat: exceptions thrown inside an @Async method do not propagate to the caller. Handle this by catching exceptions and logging them, or by implementing AsyncUncaughtExceptionHandler. For detailed @Async configuration, refer to the Spring Boot async processing guide.

Mocking JavaMailSender in Tests

If you don’t want to actually send emails during testing, mock JavaMailSender with @MockBean.

@SpringBootTest
class EmailServiceTest {

    @MockBean
    private JavaMailSender mailSender;

    @Autowired
    private EmailService emailService;

    @Test
    void sendWelcomeEmail_shouldCallSend() {
        emailService.sendWelcomeEmail("[email protected]", "太郎");
        verify(mailSender, times(1)).send(any(SimpleMailMessage.class));
    }
}

Use verify() to confirm that send() was called. For more thorough integration testing, GreenMail is a handy test SMTP server library worth looking into.

Troubleshooting Authentication Errors

Gmail-related errors tend to follow predictable patterns, so here are the key points to know.

535 Authentication Failed → You’re likely not using an App Password. Standard passwords cannot be used with accounts that have two-factor authentication enabled.

Connection timed out (port 587) → Corporate networks or ISPs sometimes block port 587. Try port 465, or check with your network administrator.

SSLHandshakeException → When using port 465, mail.smtp.ssl.enable=true is required. The configuration differs from port 587 (STARTTLS).

AuthenticationFailedException → Verify that spring.mail.username is set to your full Gmail address.

Summary

Just by adding spring-boot-starter-mail and configuring application.properties, JavaMailSender is ready to use.

  • Use SimpleMailMessage for plain text emails, MimeMessageHelper for HTML emails
  • Gmail requires an App Password for SMTP authentication (standard passwords won’t work)
  • Manage passwords via environment variables — never hardcode them
  • Add @Async to make sending asynchronous

Once the initial setup is done, email sending isn’t all that complicated — give it a try in your next project.