Duża ilość tworzonych aplikacji potrzebuje w którymś momencie wysłać maila do użytkownika. Czy to maila rejestracyjnego, czy jakieś inne powiadomienie dla użytkownika. W Spring Boocie jest do tego odpowiedni moduł (Spring Boot Starter Mail) który nam to bardzo ułatwia. W tym poście przedstawię jak go skonfigurować i użyć w przykładowym projekcie.
Kod użyty w postach dostępny jest w repozytorium GitHub pod adresem:
Przygotowanie
Aby móc zacząć wysyłać wiadomości e-mail potrzebujemy dodać do naszych zależności spring-boot-starter-mail. Następnie musimy skonfigurować dostęp do serwera pocztowego, możemy użyć własnego konta pocztowego na przykład na GMailu lub usługi takiej jak Amazon SES (Simple Email Service).
Zależności
Aby zacząć pracę z mailami, dodajemy do pom.xml spring-boot-starter-mail. Będę wykorzystywał też RESTa do uruchomienia przykładów więc od razu dodałem również spring-boot-starter-web. Cały pom.xml wygląda następująco:
<?xml version="1.0" encoding="UTF-8"?> | |
<project xmlns="http://maven.apache.org/POM/4.0.0" | |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
<modelVersion>4.0.0</modelVersion> | |
<groupId>pl.mloza</groupId> | |
<artifactId>spring-mail</artifactId> | |
<version>1.0-SNAPSHOT</version> | |
<dependencyManagement> | |
<dependencies> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-dependencies</artifactId> | |
<type>pom</type> | |
<version>2.1.6.RELEASE</version> | |
<scope>import</scope> | |
</dependency> | |
</dependencies> | |
</dependencyManagement> | |
<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> | |
<build> | |
<plugins> | |
<plugin> | |
<artifactId>maven-compiler-plugin</artifactId> | |
<version>3.6.2</version> | |
<configuration> | |
<source>10</source> | |
<target>10</target> | |
<release>10</release> | |
</configuration> | |
</plugin> | |
</plugins> | |
</build> | |
</project> |
Konfiguracja
Aby połączyć się do serwera pocztowego musimy dodać konfigurację w application.properties. Podajemy tam adres serwera, użytkownika oraz hasło. Dodatkowo powinniśmy ustawić aby połączenie było szyfrowane.
Konfiguracja Gmaila
Przykładowa konfiguracja dla gmaila wygląda następująco:
spring.mail.host=smtp.gmail.com spring.mail.port=587 spring.mail.username=<twój e-mail> spring.mail.password=<hasło aplikacji> spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true spring.mail.properties.mail.smtp.starttls.required=true
Jeśli używasz podwójnej weryfikacji w google, musisz wygenerować hasło aplikacji. Instrukcję jak to zrobić, możesz znaleźć na stronie pomocy Google: https://support.google.com/mail/answer/185833?hl=pl. W takim przypadku podajesz wygenerowane hasło zamiast hasła do Twojej skrzynki pocztowej.
Konfiguracja Amazon SES
Dla Amazon SES konfiguracja wygląda podobnie:
spring.mail.host=email-smtp.us-east-1.amazonaws.com spring.mail.username=<username> spring.mail.password=<password> spring.mail.properties.mail.transport.protocol=smtp spring.mail.properties.mail.smtp.port=25 spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true spring.mail.properties.mail.smtp.starttls.required=true
Należy pamiętać o wybraniu odpowiedniego regionu w polu host. Nazwę użytkownika i hasło generujemy w konsoli Amazonowej, która od razu nada odpowiednie uprawnienia dla wygenerowanego użytkownika. Jeśli chcemy wysyłać e-maile z różnych regionów, musimy wygenerować unikalne dane dla każdego regionu. Więcej na temat generowania danych użytkownika możesz przeczytać na stronie amazona pod adresem: https://docs.aws.amazon.com/ses/latest/DeveloperGuide/smtp-credentials.html
Wysyłanie prostego maila tekstowego
Aby wysłać maila musimy stworzyć odpowiedni serwis oraz kontroler który wywoła dla nas odpowiednią metodę serwisu po przejściu na wskazany URL.
Tworzymy email serwis
Cały kod serwisu możesz zobaczyć poniżej:
@Service | |
public class MailService { | |
private JavaMailSender javaMailSender; // 1 | |
public MailService(JavaMailSender javaMailSender) { | |
this.javaMailSender = javaMailSender; | |
} | |
public void sendSimpleEmail(String to, String subject, String content) { | |
SimpleMailMessage msg = new SimpleMailMessage(); | |
msg.setTo(to); | |
msg.setFrom("Blog Example <from@email.com>"); | |
msg.setSubject(subject); | |
msg.setText(content); | |
javaMailSender.send(msg); | |
} | |
} |
Do naszego serwisu zostaje automatycznie wstrzyknięty skonfigurowany już JavaMailSender. Następnie tworzymy sobie SimpleMailMessage, ustawiamy tytuł, adresata, zawartość wiadomości i wywołujemy send(msg). I to wystarczy aby wysłać prostą wiadomość email.
Kontroler wykorzystujący email serwis
Aby sprawdzić działanie naszego serwisu, stworzymy sobie kontroler który wywoła nam metodę sendSimpleEmail naszego serwisu i wyśle do nas wiadomość.
@RestController | |
public class MailController { | |
private MailService mailService; | |
public MailController(MailService mailService) { | |
this.mailService = mailService; | |
} | |
@GetMapping("/sendemail") | |
public String sendEmail() { | |
mailService.sendSimpleEmail("Odbiorca <odbiorca@maila.pl>", "Test e-mail", "Testing email functionality"); | |
return "E-mail sent!"; | |
} | |
} |
Tutaj już nie ma żadnej magii. Wstrzykujemy wcześniej stworzony serwis i wywołujemy metodę wysyłającą podając adresata, temat i zawartość emaila. Zauważ tylko, że adres możesz podać w formacie: nazwa odbiorcy <adres@email.pl>. Tak samo możesz podać adres nadawcy, dzięki temu w skrzynce odbiorczej adresata będzie widoczna podana nazwa, a nie tylko adres. Odbiorca będzie mógł też zobaczyć swoją nazwę w wiadomości 😉
Po uruchomieniu aplikacji i przejściu na stronę http://localhost:8080/sendemail wiadomość zostanie wysłana. W skrzynce odbiorczej powinna wyglądać mniej więcej tak jak na poniższym obrazku.

Wysyłanie maili w formacie HTML
Wysyłanie maili w formacie HTML jest tylko nieco bardziej skomplikowane niż wysyłanie prostych maili. Dodajmy do naszego serwisu kolejną metodę: sendHtmlEmail.
public void sendHtmlEmail(String to, String subject, String content) { | |
MimeMessage mail = javaMailSender.createMimeMessage(); | |
try { | |
MimeMessageHelper helper = new MimeMessageHelper(mail, true); | |
helper.setTo(to); | |
helper.setFrom("Blog example <from@email.com>"); | |
helper.setSubject(subject); | |
helper.setText(content, true); | |
} catch (MessagingException e) { | |
e.printStackTrace(); | |
} | |
javaMailSender.send(mail); | |
} |
Zamiast SimpleMailMessage używamy Message i przy wstawianiu zawartości w metodzie setText jako 2 argument podajemy true, co mówi nam, że będzie to wiadomość HTML. Musimy również obsłużyć wyjątek MesaagingException. Po tych zabiegach możemy wysłać wiadomość HTML.
Szablony HTML JTwig
Umiemy już wysyłać wiadomości w formacie HTML. Jednak jeśli chcemy stworzyć większą wiadomość, nie chcemy jej trzymać w kodzie klasy. Dodatkowo fajnie by było jakoś łatwo podmieniać zmienne w treści wiadomości. Ja do tego celu używam silnika szablonów JTwig. (Pisałem o nim szerzej w poście o widokach Springowych). Tutaj pokażę jak go wykorzystać przy wysyłaniu e-maili.
Zależności Mavena
Przed przystąpieniem do pracy z szablonami, musimy dodać odpowiednie zależności do pom.xml.
<dependency> | |
<groupId>org.jtwig</groupId> | |
<artifactId>jtwig-core</artifactId> | |
<version>5.87.0.RELEASE</version> | |
</dependency> |
Szablon HTML
Mając już zależności na miejscu, możemy przygotować sobie wiadomość którą będziemy chcieli wysyłać. Załóżmy, że znamy imię naszego użytkownika i chcielibyśmy go użyć aby się przywitać. Następnie dodamy ładny przycisk i podpis. Musimy pamiętać, że większość klientów pocztowych obsługuje tylko część HTML, do tego narzuca spore ograniczenia jeśli chodzi o style itp. Jeśli będziesz chciał tworzyć skomplikowane wiadomości polecam doczytać więcej na ten temat. Mój szablon wygląda następująco.
<h1>CzeÅÄ {{ username }}</h1> | |
<p>To jest przykÅadowy e-mail!</p> | |
<p> | |
<a href="https://blog.mloza.pl" target="_blank" style="display: inline-block; color: #ffffff; background-color: #3498db; | |
border: solid 1px #3498db; border-radius: 5px; box-sizing: border-box; cursor: pointer; text-decoration: none; | |
font-size: 14px; font-weight: bold; margin: 0 auto; padding: 12px 25px; border-color: #3498db;">Podoba mi siÄ!</a> | |
</p> | |
--<br> | |
Pozdrawiam!<br> | |
MichaÅ z blog.mloza.pl |
Najważniejszą rzeczą na którą powinieneś zwrócić uwagę jest fragment: {{ username }}. W ten sposób możemy wstawiać zmienne do szablonu. Wiadomość zapisujemy w katalogu resources, stamtąd będziemy ją mogli łatwo odczytać. Teraz musimy dodać do kontrolera kod, który wczyta nam szablon, ustawi zmienne i wygeneruje wiadomość.
Wysyłanie wiadomości
Dodajmy kolejną funkcję na nowym endpoincie która wyśle naszą wiadomość. Będzie ona wyglądać jak poniżej.
@GetMapping("/sendhtmlemail") | |
public String sendHtmlEmail() { | |
JtwigTemplate emailTemplate = JtwigTemplate.classpathTemplate("email/htmlEmail.twig"); | |
JtwigModel model = JtwigModel.newModel() | |
.with("username", "MichaÅ"); | |
String emailMessage = emailTemplate.render(model); | |
mailService.sendHtmlEmail("Michal <michal@mloza.pl>", "Test e-mail", emailMessage); | |
return "E-mail sent!"; | |
} |
Kod jest bardzo krótki. Na początku wczytujemy nasz szablon podając lokalizację. Ja trzymam szablony w katalogu resources/email. Następnie tworzymy model który będzie przechowywał nasze zmienne do użycia w szablonie. Ostatnim elementem jest wywołanie funkcji render na wiadomości, która zwróci nam wiadomośc z podstawionymi zmiennymi. Możemy w tym momencie użyć naszej funkcji sendHtmlEmail z MailService do wysłania wiadomości. Otrzymana wiadomość powinna wyglądać jak na poniższym obrazku.

Podsumowanie
W ten prosty sposób możemy wysyłać wiadomości do naszych użytkowników. Użycie szablonów JTwig pomaga nam utrzymać porządek w kodzie i jest bardzo wygodne. Istnieje wiele alternatyw dla nich jak na przykład: Thymeleaf czy Mustache. Niestety trzeba bardzo uważać przy tworzeniu wiadomości ponieważ mamy wielu klientów pocztowych którzy bardzo różnie wyświetlają wiadomości i często w różny sposób obcinają HTML w nich zawartego, a przetestowanie czy wiadomość wyświetla się poprawnie wszędzie jest trudne i czasochłonne.