Отправка электронных писем с помощью Spring

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

В рамках обучающей серии по Spring Boot в этой статье мы рассмотрим способ отправки электронных писем с помощью Spring.

Введение

Отправка электронных писем — одна из базовых функций, которая может понадобиться в любом приложении. Из этой статьи вы узнаете, как отправлять электронные письма с помощью Spring. Для отправки электронных писем вам потребуются данные SMTP-сервера. В качестве примера вы можете использовать SMTP для Gmail (имейте в виду, что у Gmail есть определенные ограничения по отправке электронной почты). Интерфейс JavaMailSender в Spring Framework предлагает простую абстракцию для отправки электронной почты, а Spring Boot производит автоматическую настройку этого интерфейса и стартового модуля.

1. Зависимости Maven

Чтобы добавить функцию автоконфигурации Spring Boot в приложение, нам нужно внести spring-boot-starter-mail в файл pom.xml. Ниже представлен фрагмент нашего файла pom.xml:

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

2. Конфигурация электронной почты

После того как мы определили зависимости, следующим шагом будет добавление конфигурации почты для автоматической настройки с помощью Spring Boot:

spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username= gmail user name
spring.mail.password= your password
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true

Приведенные выше значения конфигурации относятся к SMTP-серверу Gmail. При необходимости замените их своими

3. Служба электронной почты

Далее мы создадим простой класс службы электронной почты, который позволит нашему приложению отправлять электронные письма. В нашем примере почтовой службы мы реализуем два метода:

  1. отправка простых электронных писем;

  2. отправка электронных писем с вложением.

Наш код будет выглядеть так:

@Service
public class DefaultEmailService implements EmailService {

 @Autowired
 public JavaMailSender emailSender;

 @Override
 public void sendSimpleEmail(String toAddress, String subject, String message) {

  SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
  simpleMailMessage.setTo(toAddress);
  simpleMailMessage.setSubject(subject);
  simpleMailMessage.setText(message);
  emailSender.send(simpleMailMessage);
 }

 @Override
 public void sendEmailWithAttachment(String toAddress, String subject, String message, String attachment) throws MessagingException, FileNotFoundException {

  MimeMessage mimeMessage = emailSender.createMimeMessage();
  MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);
  messageHelper.setTo(toAddress);
  messageHelper.setSubject(subject);
  messageHelper.setText(message);
  FileSystemResource file = new FileSystemResource(ResourceUtils.getFile(attachment));
  messageHelper.addAttachment("Purchase Order", file);
  emailSender.send(mimeMessage);
 }
}

4. Тестовый контроллер

Создадим простой контроллер REST, чтобы проверить, как работает код. У нашего контроллера REST будет два метода. Сам контроллер будет выглядеть так:

package com.javadevjournal.controller;

import com.javadevjournal.email.service.EmailService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.mail.MailException;
import org.springframework.web.bind.annotation.*;

import javax.mail.MessagingException;
import java.io.FileNotFoundException;

@RestController
@RequestMapping("/email")
public class EmailController {

    private static final Logger LOG = LoggerFactory.getLogger(EmailController.class);

    @Autowired
    EmailService emailService;

    @GetMapping(value = "/simple-email/{user-email}")
    public @ResponseBody ResponseEntity sendSimpleEmail(@PathVariable("user-email") String email) {

        try {
            emailService.sendSimpleEmail(email, "Welcome", "This is a welcome email for your!!");
        } catch (MailException mailException) {
            LOG.error("Error while sending out email..{}", mailException.getStackTrace());
            return new ResponseEntity<>("Unable to send email", HttpStatus.INTERNAL_SERVER_ERROR);
        }

        return new ResponseEntity<>("Please check your inbox", HttpStatus.OK);
    }

    @GetMapping(value = "/simple-order-email/{user-email}")
    public @ResponseBody ResponseEntity sendEmailAttachment(@PathVariable("user-email") String email) {

        try {
            emailService.sendEmailWithAttachment(email, "Order Confirmation", "Thanks for your recent order",
                    "classpath:purchase_order.pdf");
        } catch (MessagingException | FileNotFoundException mailException) {
            LOG.error("Error while sending out email..{}", mailException.getStackTrace());
            return new ResponseEntity<>("Unable to send email", HttpStatus.INTERNAL_SERVER_ERROR);
        }

        return new ResponseEntity<>("Please check your inbox for order confirmation", HttpStatus.OK);
    }

}

5. Основной класс Spring Boot

@SpringBootApplication
public class SendEmailUsingSpringApplication {

   public static void main(String[] args) {
      SpringApplication.run(SendEmailUsingSpringApplication.class, args);
   }

}

Запустите приложение и перейдите по следующим ссылкам:

http://localhost:8080/email/order-email/umeshawasthi@www.javadevjournal.com
http://localhost:8080/email/simple-email/umeshawasthi@www.javadevjournal.com

6. Конфигурация SMTP-сервера Gmail

Прежде чем использовать SMTP-сервер Gmail, ознакомьтесь со следующей статьей. Из-за дополнительных мер безопасности в Gmail ваш обычный пароль от электронной почты работать не будет. 

Отправка электронных писем с помощью Spring Boot и Thymeleaf

В предыдущем разделе мы рассмотрели, как отправлять электронные письма с помощью Spring. Однако для рабочего приложения понадобится более продвинутый способ. В этом разделе мы рассмотрим, как отправлять электронные письма с помощью Spring Boot и Thymeleaf.

Thyleleaf — это шаблонизатор. Thymeleaf поможет нам отправлять электронные письма в формате HTML с широкими функциональными возможностями. Предположим, мы хотим отправить клиенту электронное письмо для подтверждения его учетной записи.

7. Класс EmailContext

Для большей универсальности создадим класс EmailContext, содержащий всю основную информацию, которая нам нужна для электронной почты. Наш класс будет выглядеть так:

public abstract class AbstractEmailContext {

    private String from;
    private String to;
    private String subject;
    private String email;
    private String attachment;
    private String fromDisplayName;
    private String emailLanguage;
    private String displayName;
    private String templateLocation;
    private Map <String, Object> context;
    //getter and seter methods
}

Рассмотрим несколько полей этого класса:

  • templateLocation — указывает расположение HTML-шаблона. Это поле понадобится нам для генерации окончательного вывода.

  • context — содержит все динамические значения, передаваемые в электронном письме. Thymeleaf будет использовать эту карту для замены выражений фактическими значениями (например, ваше имя и т. д.).

Далее мы настроим нашу службу электронной почты на обработку HTML-шаблонов Thymeleaf для наполнения электронных писем.

8. Реализация EmailService

package com.javadevjournal.core.email.service;

    import com.javadevjournal.core.email.context.AbstractEmailContext;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.mail.javamail.JavaMailSender;
    import org.springframework.mail.javamail.MimeMessageHelper;
    import org.springframework.stereotype.Service;
    import org.thymeleaf.context.Context;
    import org.thymeleaf.spring5.SpringTemplateEngine;
    
    import javax.mail.MessagingException;
    import javax.mail.internet.MimeMessage;
    import java.nio.charset.StandardCharsets;
    
    @Service
    public class DefaultEmailService implements EmailService {
    
        @Autowired
        private JavaMailSender emailSender;
    
        @Autowired
        private SpringTemplateEngine templateEngine;
    
        @Override
        public void sendMail(AbstractEmailContext email) throws MessagingException {
            MimeMessage message = emailSender.createMimeMessage();
            MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(message,
                MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED,
                StandardCharsets.UTF_8.name());
            Context context = new Context();
            context.setVariables(email.getContext());
            String emailContent = templateEngine.process(email.getTemplateLocation(), context);
    
            mimeMessageHelper.setTo(email.getTo());
            mimeMessageHelper.setSubject(email.getSubject());
            mimeMessageHelper.setFrom(email.getFrom());
            mimeMessageHelper.setText(emailContent, true);
            emailSender.send(message);
        }
    }

В приведенном выше коде есть несколько важных моментов.

  1. Мы создаем и настраиваем карту как набор переменных. Thymeleaf будет использовать этот контекст для замены заполнителей или выражений значениями, переданными через него.

  2. SpringTemplateEngine представляет собой абстракцию различных шаблонизаторов, эта функция осуществляет выбор настроенного шаблонизатора. В нашем случае это Thymeleaf.

  3. Функция templateEngine.process() отвечает за обработку и возврат результата в виде строки. Она выбирает шаблон HTML, обработает его и заменяет выражения фактическими значениями.

  4. Наконец, мы встраиваем получившийся результат в MimeMessage и заставляем почтовый сервер обрабатывать его как HTML (mimeMessageHelper.setText(emailContent, true))

9. Шаблон электронного письма

Вот наш HTML-шаблон для электронного письма (для экономии места я немного сократил HTML-код).

<!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
    <head>
        <meta charset="utf-8"> <!-- utf-8 works for most cases -->
        <meta name="viewport" content="width=device-width"> <!-- Forcing initial-scale shouldn't be necessary -->
        <meta http-equiv="X-UA-Compatible" content="IE=edge"> <!-- Use the latest (edge) version of IE rendering engine -->
        <meta name="x-apple-disable-message-reformatting">  <!-- Disable auto-scale in iOS 10 Mail entirely -->
        <title></title> <!-- The title tag shows in email notifications, like Android 4.4. -->
    
        <link href="https://fonts.googleapis.com/css?family=Lato:300,400,700" rel="stylesheet">
    
        <!-- CSS Reset : BEGIN -->
     </head>
    
    <body width="100%" style="margin: 0; padding: 0 !important; mso-line-height-rule: exactly; background-color: #f1f1f1;">
    <center style="width: 100%; background-color: #f1f1f1;">
        <div style="display: none; font-size: 1px;max-height: 0px; max-width: 0px; opacity: 0; overflow: hidden; mso-hide: all; font-family: sans-serif;">
            &zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;
        </div>
        <div style="max-width: 600px; margin: 0 auto;" class="email-container">
            <!-- BEGIN BODY -->
            <table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="margin: auto;">
                <tr>
                    <td valign="top" class="bg_white" style="padding: 1em 2.5em 0 2.5em;">
                        <table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
                            <tr>
                                <td class="logo" style="text-align: center;">
                                    <h1>Welcome</h1>
                                </td>
                            </tr>
                        </table>
                    </td>
                </tr><!-- end tr -->
                <tr>
                    <td valign="middle" class="hero bg_white" style="padding: 2em 0 4em 0;">
                        <table>
                            <tr>
                                <td>
                                    <div class="text" style="padding: 0 2.5em; text-align: center;">
                                        <h2>Finish creating your account.</h2>
                                        <h3>Hi<p th:text="${firstName}"></h3>
                                        <h3>We're excited to have you get started. First, you need to confirm your account. Just press the button below.</h3>
                                        <p><a th:href="${verificationURL}" class="btn btn-primary">Validate Account</a></p>
                                    </div>
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    <div class="text" style="padding: 0 2.5em; text-align: center;">
                                        <h3>if you experience any issues with the button above, copy and paste the URL below into your web browser.</h3>
                                        <p th:text="${verificationURL}"></p>
                                    </div>
                                </td>
                            </tr>
                        </table>
                    </td>
                </tr><!-- end tr -->
                <!-- 1 Column Text + Button : END -->
            </table>
            <table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="margin: auto;">
                <tr>
                    <td valign="middle" class="bg_light footer email-section">
                        <table>
                            <tr>
                                <td valign="top" width="33.333%" style="padding-top: 20px;">
                                    <table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
                                        <tr>
                                            <td style="text-align: left; padding-right: 10px;">
                                                <h3 class="heading">About</h3>
                                                <p>Welcome to Java Development Journal Blog. We publish articles on
                                                    Spring, Spring Boot and Spring Security.
                                                </p>
                                            </td>
                                        </tr>
                                    </table>
                                </td>
                                <td valign="top" width="33.333%" style="padding-top: 20px;">
                                    <table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
                                        <tr>
                                            <td style="text-align: left; padding-left: 5px; padding-right: 5px;">
                                                <h3 class="heading">Contact Info</h3>
                                                <ul>
                                                    <li><span class="text">Java Development Journal</span></li>
                                                </ul>
                                            </td>
                                        </tr>
                                    </table>
                                </td>
                                <td valign="top" width="33.333%" style="padding-top: 20px;">
                                    <table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
                                        <tr>
                                            <td style="text-align: left; padding-left: 10px;">
                                                <h3 class="heading">Useful Links</h3>
                                                <ul>
                                                    <li><a href="#">Home</a></li>
                                                    <li><a href="#">About</a></li>
                                                </ul>
                                            </td>
                                        </tr>
                                    </table>
                                </td>
                            </tr>
                        </table>
                    </td>
                </tr><!-- end: tr -->
            </table>
    
        </div>
    </center>
    </body>
    </html>

Имейте в виду, что необходимо внести в контекст значения для ${firstName} и ${verifyURL}, чтобы Thymeleaf мог подставить фактические значения для этих переменных во время обработки.

Резюме

В этой статье мы узнали, как отправлять электронные письма с помощью Spring. Мы узнали, каким образом можно реализовать функции электронной почты с применением автоконфигурации Spring Boot. Исходный код, приведенный в этом посте, доступен на GitHub.


Перевод материала подготовили в преддверии старта курса онлайн-курса «Разработчик на Spring Framework».

Приглашаем также всех желающих на открытый вебинар «Spring в Docker. Практические советы». На занятии мы рассмотрим всем известную тему по запуску Spring-приложений в Docker-контейнере и не всем известные решения возникающих задач.

Источник: https://habr.com/ru/company/otus/blog/557798/


Интересные статьи

Интересные статьи

Одной из первых задач для большинства бизнес-приложений на ASP.NET Core является реализация операций CRUD (Create, Read, Update, Delete) для основных объектов, с которыми работает ваше ...
Вы когда-нибудь задумывались, как обеспечить энергией gps-трекер для отслеживания миграции диких животных? Оленю солнечную батарею на рога не повесишь… Или как быть с дру...
Подкасты – канал, который активно развивается весь 2020 год. Растет объем аудитории, да и самих подкастов становится все больше. При этом единого аудиторного измерителя слушателей не суще...
Случайности. Для кого-то все, что происходит вокруг, это одна сплошная случайность. А кто-то утверждает, что случайностей не бывает. Философствовать и спорить на эту тему можно много ...
Решил написать статью об очень простом устройстве, сделанным за два вечера. Решило оно давнюю проблему, чему я сильно рад и использую его по сей день. Отработало исправно оно около 3 месяцев. Соб...