Skip to content

Sending Emails with Spring Boot and Gmail SMTP

This document details the process of configuring and sending emails in a Spring Boot application using the Gmail SMTP server.

1. Enabling Gmail SMTP and Generating an App Password

To use Gmail's SMTP in an external application, you need an "App Password" if you have 2-Step Verification enabled. It is highly recommended to have 2-Step Verification enabled for greater security.

Step-by-Step to Generate an App Password:

  1. Access your Google Account: Go to myaccount.google.com.
  2. Go to Security: In the left-side menu, click on "Security".
  3. 2-Step Verification: Scroll down to the "How you sign in to Google" section and click on "2-Step Verification". If it's not already enabled, follow the instructions to activate it.
  4. App passwords: After enabling 2-Step Verification, return to the "Security" screen and look for "App passwords". Click on it.
  5. Generate New App Password:
    • Select "Mail" from the "Select app" dropdown menu.
    • Select "Other (Custom name)" from the "Select device" dropdown menu and type a name like "Spring Boot Email" (optional, for identification purposes only).
    • Click "Generate".
  6. Copy the App Password: A 16-character password will be displayed in a yellow box. Copy this password and save it in a secure place. This will be the password you use in your Spring Boot application, not your Google account password.

Note: If you do not want to enable 2-Step Verification, you would have to enable the "Less secure app access" option in your Google security settings. However, this option has been discontinued for personal accounts as of May 30, 2022, and is not recommended for security reasons. Always prefer using "App passwords".

2. Configuring the Spring Boot Project

2.1. Add Spring Mail Dependency

Add the spring-boot-starter-mail dependency to your pom.xml file.

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

2.2. Configure Gmail Properties in application.properties

In the src/main/resources/application.properties file, add the following settings:

application.properties:

# Gmail SMTP Server Properties
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=${EMAIL_USER} # Your Gmail address in an environment variable
spring.mail.password=${EMAIL_SENHA} # The previously generated app password in an environment variable

# Additional properties for secure SMTP (TLS)
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=5000
spring.mail.properties.mail.smtp.writetimeout=5000

organize your environment variables

3. Creating the Email Service

Create a service class to handle email sending.

// src/main/java/com/example/emaildemo/service/EmailService.java
package com.example.emaildemo.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

@Service
public class EmailService {

    @Autowired
    private JavaMailSender mailSender;

    /**
     * Sends a simple email.
     * @param to The recipient of the email.
     * @param subject The subject of the email.
     * @param text The body of the email.
     */
    public void sendSimpleEmail(String to, String subject, String text) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom("your_email@gmail.com"); // Can be read from application.properties configuration
        message.setTo(to);
        message.setSubject(subject);
        message.setText(text);
        mailSender.send(message);
        System.out.println("Email sent successfully to: " + to);
    }

    // You can add methods to send emails with HTML, attachments, etc.
    // Example of sending an email with HTML (requires MimeMessageHelper)
    /*
    import jakarta.mail.internet.MimeMessage;
    import org.springframework.mail.javamail.MimeMessageHelper;

    public void sendHtmlEmail(String to, String subject, String htmlContent) {
        try {
            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8"); // true for multipart/mixed
            helper.setFrom("your_email@gmail.com");
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(htmlContent, true); // true indicates the content is HTML
            mailSender.send(message);
            System.out.println("HTML email sent successfully to: " + to);
        } catch (jakarta.mail.MessagingException e) {
            e.printStackTrace();
            // Handle the exception
        }
    }
    */
}

ThymeLeaf: Additionally, if you want to send rich HTML emails, you can use a template engine like Thymeleaf.

5. Important Considerations and Best Practices

  • Credential Security:
    • Never hardcode credentials directly in the source code in a production environment.
    • For production environments, use environment variables, Spring Cloud Config, HashiCorp Vault, or other secret management services to inject credentials.
    • If you are using Docker, you can use Docker secrets.
  • Exception Handling: Implement robust exception handling to deal with email sending failures (e.g., network, authentication, etc.).
  • Logs: Configure logs to record the status of email sending, including successes and failures, for debugging and auditing purposes.
  • Asynchronous Processing: To avoid blocking your application's main thread (especially in web requests), consider sending emails asynchronously using @Async and @EnableAsync in your main configuration class.
    • Add @EnableAsync to your main class (the one with @SpringBootApplication).
    • Add @Async to the sendSimpleEmail method in EmailService.
  • Email Templates: For more complex emails or those with HTML formatting, use template libraries like Thymeleaf, FreeMarker, or Mustache to create email templates and populate them dynamically.
  • Production Settings: In production, ensure your firewall allows outgoing connections on port 587 (or 465 for SSL).
  • Gmail Limits: Be aware of Gmail's daily sending limits (usually 500 emails per day for personal accounts). For larger volumes, consider transactional email services like SendGrid, Mailgun, AWS SES, etc.

Setting up Environment Variables


Setting environment variables is crucial for keeping credentials secure and making your Spring Boot application's configurations flexible across different environments. Below is a concise explanation of how to do this for EMAIL_USER and EMAIL_SENHA on Windows, macOS, and in Docker Compose.

Windows

On Windows, you can set environment variables temporarily via the command line or permanently through the system settings.

Temporarily (for the current terminal session):

Open Command Prompt or PowerShell and use:

set EMAIL_USER=your_email@gmail.com
set EMAIL_SENHA=your_app_password

Or in PowerShell:

$env:EMAIL_USER="your_email@gmail.com"
$env:EMAIL_SENHA="your_app_password"

Then, run your Spring Boot application from the same terminal.

Permanently (System-wide):

  1. Search for "Environment Variables" in the Start Menu and select "Edit the system environment variables".
  2. In the "System Properties" window, click on "Environment Variables...".
  3. In the "User variables for " or "System variables" section, click "New..." to add EMAIL_USER and EMAIL_SENHA with their respective values.
  4. Click "OK" on all windows to save the changes. You may need to restart your system or terminal for the changes to take effect.

macOS

On macOS, environment variables can be set temporarily in the terminal session or added to shell configuration files to make them persistent.

Temporarily (for the current terminal session):

Open Terminal and use:

export EMAIL_USER="your_email@gmail.com"
export EMAIL_SENHA="your_app_password"

Then, run your Spring Boot application from the same terminal.

Permanently (User Profile):

To have the variables load automatically with each new terminal session, add the export lines to one of the following files in your home directory:

  • ~/.bash_profile (if you use Bash as your default shell)
  • ~/.zshrc (if you use Zsh as your default shell, which is the default on macOS Catalina and later)

Example for ~/.zshrc:

echo 'export EMAIL_USER="your_email@gmail.com"' >> ~/.zshrc
echo 'export EMAIL_SENHA="your_app_password"' >> ~/.zshrc
source ~/.zshrc # To apply the changes immediately

Docker Compose

In Docker Compose, you can define environment variables in a few ways in your docker-compose.yml file. The most common and recommended way for credentials is to use an .env file.

  1. Create a file named .env in the same directory as your docker-compose.yml.
  2. Add your environment variables to this file, one per line:

    # .env
    EMAIL_USER=your_email@gmail.com
    EMAIL_SENHA=your_app_password
    
  3. In your docker-compose.yml file, reference these variables. Docker Compose will automatically load variables from an .env file in the same directory.

    # docker-compose.yml
    version: '3.8'
    services:
      my-spring-app:
        image: your-spring-boot-image:latest # Or use build: . if building the image
        ports:
          - "8080:8080"
        environment:
          # These variables will be read from the .env file
          - EMAIL_USER=${EMAIL_USER}
          - EMAIL_SENHA=${EMAIL_SENHA}
    
  4. Run your Docker Compose service: docker-compose up -d.

Alternative (less recommended for sensitive credentials in version control):

You can also define the variables directly in the docker-compose.yml under the environment section, but this exposes the values in the file.

# docker-compose.yml
services:
  my-spring-app:
    image: your-spring-boot-image:latest
    ports:
      - "8080:8080"
    environment:
      EMAIL_USER: your_email@gmail.com
      EMAIL_SENHA: your_app_password # Avoid this in production

Always prefer the .env file method and make sure to add it to your .gitignore to prevent your credentials from being committed to version control.