Spring Boot Aufbau – Tag 7 von 10
Von Elyndra Valen, Senior Entwicklerin bei Java Fleet Systems Consulting

🗺️ Deine Position im Kurs
| Tag | Thema | Status |
|---|---|---|
| 1 | Auto-Configuration & Custom Starter | ✅ Abgeschlossen |
| 2 | Spring Data JPA Basics | ✅ Abgeschlossen |
| 3 | JPA Relationships & Queries | ✅ Abgeschlossen |
| 4 | Spring Security Part 1 – Authentication | ✅ Abgeschlossen |
| 5 | Spring Security Part 2 – Authorization | ✅ Abgeschlossen |
| 6 | Spring Boot Caching & JSON | ✅ Abgeschlossen |
| → 7 | Messaging & Email | 👉 DU BIST HIER! |
| 8 | Testing & Dokumentation | 📜 Kommt als nächstes |
| 9 | Spring Boot Actuator | 🔒 Noch nicht freigeschaltet |
| 10 | Template Engines & Microservices | 🔒 Noch nicht freigeschaltet |
Modul: Spring Boot Aufbau
Gesamt-Dauer: 10 Arbeitstage (je 8 Stunden)
Dauer heute: 8 Stunden
Dein Ziel: Email-Versand und asynchrone Kommunikation implementieren
📋 Voraussetzungen für diesen Tag
Du brauchst:
- ✅ Java JDK 21 installiert
- ✅ Maven 3.8+ oder deine IDE
- ✅ Docker (für MailDev – empfohlen!)
- ✅ Grundlegendes Spring Boot Verständnis (Tage 1-6)
Optional (hilft beim Verständnis):
- SMTP-Grundkenntnisse
- Thread-Konzepte in Java
Tag verpasst oder später eingestiegen?
Kein Problem! Dieser Blogbeitrag deckt genau den Stoff von Tag 7 ab. Lade das Projekt herunter und arbeite die 8 Stunden durch!
⚡ Kurze Zusammenfassung – Das Wichtigste in 30 Sekunden
Heute lernst du:
- ✅ Email-Versand mit Spring Boot Mail und JavaMailSender
- ✅ HTML-Emails mit Thymeleaf Templates erstellen
- ✅ Asynchronen Email-Versand für bessere Performance
- ✅ JMS Messaging mit Artemis nutzen
- ✅ Message-Driven Architecture verstehen
Das Problem: User-Registrierung dauert 5 Sekunden, weil Email synchron versendet wird.
Die Lösung: Asynchroner Email-Versand oder JMS – User bekommt sofort Response!
💡 Was du heute baust
Einen Email-Service, der Welcome-Emails versendet wenn sich User registrieren. Du lernst den Unterschied zwischen synchronem UND asynchronem Email-Versand, erstellst HTML-Templates und verstehst Message-Driven Architecture!
Dein Tagesziel: Nach 8 Stunden kannst du Emails versenden, HTML-Templates nutzen und verstehst, warum asynchrone Kommunikation wichtig ist.
📧 Warum Email & Messaging?
Hi! 👋
Elyndra hier. Letzte Woche hatte ich ein interessantes Problem: Eine User-Registrierung brauchte 5 Sekunden Response-Zeit. 5 Sekunden! Der User wartete und wartete… warum?
Weil wir die Welcome-Email synchron versendet haben. Der Server hat buchstäblich gewartet, bis die Email raus war, bevor er dem User „Registrierung erfolgreich“ zurückgegeben hat.
Das Aha-Erlebnis: Als ich den Email-Versand asynchron gemacht habe, war die Response-Zeit bei 200ms. Der User war glücklich, die Email kam trotzdem an, und der Server konnte sich um andere Requests kümmern.
Heute lernst du genau das:
- Wie man Emails versendet (sync und async)
- Wie man HTML-Templates nutzt
- Wie man mit JMS Messages zwischen Services schickt
- Warum asynchrone Kommunikation wichtig ist
Zeit, loszulegen! 🔧
🟢 GRUNDLAGEN – Deine ersten Schritte
Schritt 1: Projekt-Setup
Was du brauchst:
Öffne dein pom.xml und füge diese Dependencies hinzu:
<!-- Spring Boot Mail -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- Thymeleaf für Email-Templates -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- Artemis für JMS (später) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-artemis</artifactId>
</dependency>
Was macht was?
spring-boot-starter-mail– Ermöglicht Email-Versandspring-boot-starter-thymeleaf– Für HTML-Templatesspring-boot-starter-artemis– Für Message-Queues (kommt später)
✅ Checkpoint: Dependencies hinzugefügt? Mach ein mvn clean install um sie herunterzuladen!
Schritt 2: MailDev aufsetzen (WICHTIG!)
Was ist MailDev?
MailDev ist ein Test-Email-Server. Alle Emails, die du sendest, werden abgefangen und in einer Web-UI angezeigt – kein echter Email-Versand! Perfekt für Development!
Analogie: Stell dir vor, du wirfst Briefe in einen Briefkasten, aber die Briefe landen nicht bei der Post, sondern in einer Sammelbox, die du jederzeit öffnen kannst.
MailDev starten:
# Mit Docker (einfachster Weg) docker run -p 1080:1080 -p 1025:1025 maildev/maildev
Was passiert hier?
- Port
1025– SMTP-Server (für Email-Versand) - Port
1080– Web-UI (zum Emails ansehen)
✅ Checkpoint:
- Öffne http://localhost:1080 – siehst du die MailDev-Oberfläche?
- Wenn ja: Perfekt! Weiter geht’s!
- Wenn nein: Ist Docker gestartet? Läuft MailDev?
docker pszeigt laufende Container.
Schritt 3: Spring Boot konfigurieren
application.properties bearbeiten:
Öffne src/main/resources/application.properties und füge hinzu:
# SMTP-Server (MailDev) spring.mail.host=localhost spring.mail.port=1025 spring.mail.from=noreply@javafleet.de # Logging (damit du siehst was passiert) logging.level.de.javafleet.messaging=INFO
Was bedeutet das?
spring.mail.host– Wo ist der SMTP-Server? (localhost = dein PC)spring.mail.port– Auf welchem Port? (1025 = MailDev)spring.mail.from– Von welcher Absender-Adresse?
✅ Checkpoint: Properties gespeichert? Weiter!
Schritt 4: Erste simple Email versenden
EmailService erstellen:
Erstelle eine neue Klasse EmailService.java:
package de.javafleet.messaging.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
@Slf4j
public class EmailService {
private final JavaMailSender mailSender;
public void sendSimpleEmail(String to, String subject, String text) {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom("noreply@javafleet.de");
message.setTo(to);
message.setSubject(subject);
message.setText(text);
log.info("📧 Sending email to: {}", to);
mailSender.send(message);
log.info("✅ Email sent successfully!");
}
}
Erklärung Zeile für Zeile:
@Service– Spring verwaltet diese KlasseJavaMailSender– Spring injiziert automatisch den Email-SenderSimpleMailMessage– Einfache Text-Email (kein HTML)message.setFrom(...)– Absender-Adressemessage.setTo(...)– Empfänger-Adressemessage.setSubject(...)– Email-Betreffmessage.setText(...)– Email-TextmailSender.send(...)– JETZT wird die Email verschickt!
✅ Checkpoint: Service erstellt? Kompiliert es? (mvn compile)
Schritt 5: Controller zum Testen erstellen
MessagingController erstellen:
package de.javafleet.messaging.controller;
import de.javafleet.messaging.service.EmailService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
@RequestMapping("/api/email")
@RequiredArgsConstructor
public class MessagingController {
private final EmailService emailService;
@PostMapping("/send")
public Map<String, String> sendEmail(
@RequestParam String to,
@RequestParam String subject,
@RequestParam String text) {
emailService.sendSimpleEmail(to, subject, text);
return Map.of(
"status", "success",
"message", "Email sent to " + to
);
}
}
Was macht dieser Controller?
@RestController– Macht diese Klasse zu einem REST-Endpoint@PostMapping("/send")– POST-Request auf/api/email/send@RequestParam– Holt Parameter aus der URLemailService.sendSimpleEmail(...)– Ruft unseren Service auf
✅ Checkpoint: Controller erstellt? Spring Boot starten: mvn spring-boot:run
Schritt 6: Erste Email versenden! 🎉
Teste es mit curl:
curl -X POST "http://localhost:8080/api/email/send" \ -d "to=test@example.com" \ -d "subject=Hello from Spring Boot" \ -d "text=This is my first email!"
Was sollte passieren:
- In der Console siehst du:
📧 Sending email to: test@example.com ✅ Email sent successfully!
- curl zeigt:
{"status":"success","message":"Email sent to test@example.com"}
- In MailDev (http://localhost:1080) siehst du die Email!
✅ Checkpoint:
- [ ] Email in MailDev angekommen?
- [ ] Betreff und Text korrekt?
- [ ] Funktioniert alles?
Wenn ja: GLÜCKWUNSCH! 🎉 Du hast deine erste Email mit Spring Boot versendet!
Wenn nein:
- MailDev läuft?
docker ps - Spring Boot läuft? Keine Fehler in der Console?
- Port 8080 frei? Anderer Service läuft da?
Schritt 7: HTML-Email mit Template
Warum HTML?
Text-Emails sind langweilig! Mit HTML kannst du:
- ✅ Farben und Styling nutzen
- ✅ Buttons einfügen
- ✅ Bilder anzeigen
- ✅ Professioneller aussehen
Thymeleaf Template erstellen:
Erstelle src/main/resources/templates/email/welcome.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
}
.container {
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.header {
background-color: #4CAF50;
color: white;
padding: 20px;
text-align: center;
}
.content {
background-color: white;
padding: 20px;
}
.button {
background-color: #4CAF50;
color: white;
padding: 10px 20px;
text-decoration: none;
display: inline-block;
border-radius: 5px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🚀 Willkommen bei Java Fleet!</h1>
</div>
<div class="content">
<h2>Hallo <span th:text="${username}">User</span>! 👋</h2>
<p>Willkommen an Bord! Wir freuen uns, dass du dich registriert hast.</p>
<p><strong>Email:</strong> <span th:text="${email}">email@example.com</span></p>
<a href="#" class="button">Zum Dashboard</a>
</div>
</div>
</body>
</html>
Was ist hier besonders?
th:text="${username}"– Thymeleaf-Variable (wird durch echten Wert ersetzt)${email}– Weitere Variable- Inline-CSS für Styling
✅ Checkpoint: Template erstellt? Ordner templates/email/ existiert?
Schritt 8: HTML-Email versenden
EmailService erweitern:
Füge diese Methode zu EmailService.java hinzu:
@Autowired
private SpringTemplateEngine templateEngine;
@Value("${spring.mail.from}")
private String fromEmail;
public void sendHtmlEmail(String to, String subject, String username, String email) {
try {
// Thymeleaf Context mit Variablen
Context context = new Context();
context.setVariable("username", username);
context.setVariable("email", email);
// Template verarbeiten
String htmlContent = templateEngine.process("email/welcome", context);
// HTML-Email erstellen
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
helper.setFrom(fromEmail);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(htmlContent, true); // true = HTML!
log.info("📧 Sending HTML email to: {}", to);
mailSender.send(mimeMessage);
log.info("✅ HTML email sent!");
} catch (MessagingException e) {
log.error("❌ Failed to send HTML email", e);
}
}
Erklärung:
Context– Container für Template-VariablentemplateEngine.process(...)– Verwandelt Template in HTMLMimeMessage– Komplexere Email (HTML, Attachments, etc.)helper.setText(..., true)–truebedeutet „Das ist HTML!“
Imports nicht vergessen:
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.mail.javamail.MimeMessageHelper; import org.thymeleaf.context.Context; import org.thymeleaf.spring6.SpringTemplateEngine; import jakarta.mail.MessagingException; import jakarta.mail.internet.MimeMessage;
✅ Checkpoint: Code kompiliert? Keine Errors?
Schritt 9: HTML-Email testen
Controller erweitern:
Füge zu MessagingController.java hinzu:
@PostMapping("/send-html")
public Map<String, String> sendHtmlEmail(
@RequestParam String to,
@RequestParam String username) {
emailService.sendHtmlEmail(
to,
"Willkommen bei Java Fleet!",
username,
to
);
return Map.of(
"status", "success",
"message", "HTML email sent to " + to
);
}
Teste es:
curl -X POST "http://localhost:8080/api/email/send-html" \ -d "to=nova@javafleet.de" \ -d "username=Nova"
Check MailDev (http://localhost:1080):
- Email ist schön formatiert?
- Grüner Header sichtbar?
- Username „Nova“ wird angezeigt?
✅ Checkpoint:
- [ ] HTML-Email angekommen?
- [ ] Styling funktioniert?
- [ ] Variablen wurden ersetzt?
Wenn ja: SUPER! 🎉 Du kannst jetzt HTML-Emails versenden!
🟢 GRUNDLAGEN – Zwischencheckpoint
Kontrolliere:
- [ ] MailDev läuft
- [ ] Erste simple Email versendet
- [ ] HTML-Email mit Template erstellt
- [ ] Template-Variablen funktionieren
- [ ] Alles kompiliert ohne Fehler
Alle ✅? Perfekt! Du verstehst die Grundlagen!
Probleme? Schau nochmal die Schritte 1-9 durch. Jeder Schritt muss funktionieren!
Pause Zeit! ☕ Nimm dir 10 Minuten Pause. Du hast es verdient!
🟡 PROFESSIONALS – Production-Ready Skills
Jetzt wird’s ernst! Du verstehst Email-Versand – Zeit für echte Projekt-Szenarien!
Best Practice #1: Asynchroner Email-Versand
Das Problem:
Aktuell wartet dein Server, bis die Email verschickt ist:
public User registerUser(UserDTO dto) {
User user = repository.save(dto.toEntity());
emailService.sendHtmlEmail(...); // Server wartet hier 2-5 Sekunden!
return user; // User muss warten!
}
User-Perspektive: „Warum dauert die Registrierung so lange? 😤“
Die Lösung: @Async
// In EmailService.java
@Async
public void sendHtmlEmailAsync(String to, String subject,
String username, String email) {
// Gleicher Code wie vorher
sendHtmlEmail(to, subject, username, email);
}
Main Application aktivieren:
@SpringBootApplication
@EnableAsync // <- Das ist wichtig!
public class MessagingEmailApplication {
public static void main(String[] args) {
SpringApplication.run(MessagingEmailApplication.class, args);
}
}
Jetzt verwenden:
public User registerUser(UserDTO dto) {
User user = repository.save(dto.toEntity());
emailService.sendHtmlEmailAsync(...); // Returns SOFORT!
return user; // User wartet nicht!
}
Was passiert?
- User wird gespeichert
- Email-Methode wird in separatem Thread gestartet
- Methode returned SOFORT
- Email wird im Hintergrund verschickt
Warum funktioniert das besser?
- ✅ User bekommt sofort Response (200-300ms statt 5 Sekunden)
- ✅ Server kann sich um andere Requests kümmern
- ✅ Email kommt trotzdem an
✅ Checkpoint:
- [ ]
@EnableAsyncin Main-Klasse? - [ ]
@Asyncauf Email-Methode? - [ ] Teste: Ist die Response jetzt schneller?
Best Practice #2: Error-Handling
Häufiger Fehler:
// ❌ Was wenn SMTP-Server down ist?
@Async
public void sendEmail(...) {
mailSender.send(message); // Kann Exception werfen!
}
Production-Ready Lösung:
@Async
public void sendHtmlEmailAsync(String to, String subject,
String username, String email) {
try {
sendHtmlEmail(to, subject, username, email);
log.info("✅ Async email sent to: {}", to);
} catch (Exception e) {
log.error("❌ Failed to send email to: {}", to, e);
// In Production: Zu Dead Letter Queue senden
// Oder: Retry-Mechanismus
}
}
Warum?
- SMTP-Server kann offline sein
- Netzwerk-Probleme
- Falsche Email-Adresse
- Exception darf nicht die ganze App crashen!
✅ Checkpoint: Error-Handling eingebaut? Teste: Was passiert bei falscher SMTP-Config?
Best Practice #3: Thread Pool Konfiguration
Problem:
Standard @Async nutzt unlimited Threads. Bei 1000 Emails = 1000 Threads = Server-Crash!
Lösung: Thread Pool konfigurieren:
@Configuration
public class AsyncConfig {
@Bean(name = "taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2); // Minimum 2 Threads
executor.setMaxPoolSize(5); // Maximum 5 Threads
executor.setQueueCapacity(100); // 100 Tasks in Queue
executor.setThreadNamePrefix("async-email-");
executor.initialize();
return executor;
}
}
Was bedeutet das?
CorePoolSize– Immer 2 Threads bereitMaxPoolSize– Maximal 5 Threads gleichzeitigQueueCapacity– Bis zu 100 Tasks warten in Queue
Analogie: Du hast 5 Kassierer (Threads). Maximal 5 Kunden werden gleichzeitig bedient. 100 weitere Kunden warten in der Schlange (Queue).
✅ Checkpoint: Config erstellt? Spring Boot startet ohne Fehler?
Real-World-Szenario: User-Registrierung
Situation:
User registriert sich → Welcome-Email soll raus.
Complete Implementation:
1. UserService.java:
@Service
@RequiredArgsConstructor
@Slf4j
public class UserService {
private final UserRepository userRepository;
private final EmailService emailService;
@Transactional
public User registerUser(UserDTO dto) {
// Prüfen: Email existiert schon?
if (userRepository.existsByEmail(dto.getEmail())) {
throw new IllegalArgumentException("Email already exists!");
}
// User speichern
User user = userRepository.save(dto.toEntity());
log.info("💾 User saved: {}", user.getId());
// Email ASYNCHRON versenden
emailService.sendWelcomeEmailAsync(user);
log.info("⚡ Welcome email triggered (async)");
return user;
}
}
2. Controller:
@PostMapping("/users/register")
public ResponseEntity<Map<String, Object>> registerUser(
@Valid @RequestBody UserDTO dto) {
long start = System.currentTimeMillis();
User user = userService.registerUser(dto);
long duration = System.currentTimeMillis() - start;
return ResponseEntity.status(HttpStatus.CREATED).body(Map.of(
"status", "success",
"userId", user.getId(),
"email", user.getEmail(),
"durationMs", duration // Zeigt: Sehr schnell!
));
}
Teste es:
curl -X POST http://localhost:8080/api/users/register \
-H "Content-Type: application/json" \
-d '{
"username": "testuser",
"email": "test@example.com",
"password": "password123"
}'
Response:
{
"status": "success",
"userId": 1,
"email": "test@example.com",
"durationMs": 150 ← Sehr schnell!
}
Check MailDev: Welcome-Email ist da! (kommt nach 1-2 Sekunden an)
✅ Checkpoint:
- [ ] User-Registrierung funktioniert?
- [ ] Response-Zeit < 500ms?
- [ ] Email kommt trotzdem an?
Häufige Probleme & Lösungen
Problem 1: @Async funktioniert nicht
Email wird synchron versendet, nicht async!
Lösung:
@EnableAsyncin Main-Klasse vorhanden?- Methode ist
public? - Methode wird nicht von derselben Klasse aufgerufen?
Wichtig: @Async funktioniert nur bei Aufrufen von außen!
// ❌ Funktioniert NICHT:
public void method1() {
this.asyncMethod(); // Same class!
}
// ✅ Funktioniert:
public void method1() {
someOtherService.asyncMethod(); // Different class!
}
Problem 2: Email wird nicht versendet
Lösung-Checkliste:
- MailDev läuft?
docker ps - Port 1025 frei?
netstat -an | grep 1025 - application.properties korrekt?
- Logs checken: Gibt es Exceptions?
Problem 3: Template nicht gefunden
TemplateNotFoundException: email/welcome
Lösung:
- Template liegt in
src/main/resources/templates/email/welcome.html? - Ordner heißt templates, nicht template?
- Maven:
mvn clean install(repackaged Ressourcen)
🟡 PROFESSIONALS – Zwischencheckpoint
Kontrolliere:
- [ ] @Async Email-Versand implementiert
- [ ] Error-Handling eingebaut
- [ ] Thread Pool konfiguriert
- [ ] User-Registrierung mit async Email funktioniert
- [ ] Response-Zeit deutlich schneller
Alle ✅? Du bist Production-Ready! 🚀
Pause! ☕
Nimm dir 10 Minuten. Der Bonus-Teil kommt gleich!
🔵 BONUS – Für die Neugierigen
Du hast die Basics drauf und bist Production-Ready?
Perfekt! Hier ist noch mehr, wenn du tiefer eintauchen willst.
⚠️ Optional! Überspringe diesen Teil, wenn dir der Kopf raucht.
Du kannst später zurückkommen.
Advanced Feature: JMS Messaging
Was ist JMS?
JMS = Java Message Service. Eine Queue für Messages zwischen Services.
Analogie:
- @Async: Brief direkt übergeben (vergessen bei Neustart)
- JMS: Brief in Briefkasten (überlebt Neustart, automatic Retry)
Wann brauchst du JMS?
- Messages sollen persistent sein (überleben Restart)
- Retry bei Fehlern automatisch
- Microservices kommunizieren miteinander
- Guaranteed Delivery wichtig
Aktivieren:
In application.properties:
# JMS mit embedded Artemis spring.artemis.mode=embedded spring.jms.pub-sub-domain=false
Main Application:
@SpringBootApplication
@EnableAsync
@EnableJms // <- JMS aktivieren!
public class MessagingEmailApplication {
// ...
}
Message Producer:
@Service
@RequiredArgsConstructor
public class UserService {
private final JmsTemplate jmsTemplate;
public User registerUserWithJMS(UserDTO dto) {
User user = userRepository.save(dto.toEntity());
// Message zu Queue senden
jmsTemplate.convertAndSend("user.registered", user);
log.info("📨 JMS: Message sent to queue");
return user;
}
}
Message Consumer:
@Component
@RequiredArgsConstructor
@Slf4j
public class UserRegistrationListener {
private final EmailService emailService;
@JmsListener(destination = "user.registered")
public void handleUserRegistration(User user) {
log.info("📬 JMS: Received message for: {}", user.getEmail());
emailService.sendWelcomeEmail(user);
}
}
Was passiert?
- User wird registriert
- Message wird in Queue „user.registered“ gelegt
- Listener nimmt Message aus Queue
- Email wird versendet
- Bei Fehler: Automatic Retry!
Vorteile:
- ✅ Messages überleben Server-Restart
- ✅ Automatic Retry bei Fehlern
- ✅ Guaranteed Delivery
- ✅ Mehrere Listener möglich
Nachteil:
- 🐢 Langsamer als @Async
- Braucht Message-Broker (Artemis/RabbitMQ/Kafka)
✅ Bonus-Checkpoint:
- [ ] JMS aktiviert?
- [ ] Message wird in Queue gelegt?
- [ ] Listener empfängt Message?
- [ ] Email wird versendet?
Merke dir: Du musst JMS NICHT jetzt verstehen. Komm zurück, wenn du Microservices baust!
Performance-Optimierung: Batch-Email-Versand
Problem:
1000 Emails einzeln versenden = 1000 SMTP-Connections = langsam!
Lösung: Batch-Versand
public void sendBatchEmails(List<User> users) {
MimeMessage[] messages = new MimeMessage[users.size()];
for (int i = 0; i < users.size(); i++) {
messages[i] = createEmailFor(users.get(i));
}
// Alle auf einmal senden!
mailSender.send(messages);
log.info("📨 Sent {} emails in batch", users.size());
}
Performance:
- Einzeln: 1000 Emails = 30-60 Sekunden
- Batch: 1000 Emails = 5-10 Sekunden
Wann nutzen?
- Newsletter-Versand
- Massenmails
- Reports an viele User
Tiefenwissen: Spring Events als Alternative
Was sind Spring Events?
In-Memory Events innerhalb einer Spring Boot App. Keine externe Queue.
Event erstellen:
public class UserRegisteredEvent extends ApplicationEvent {
private final User user;
public UserRegisteredEvent(Object source, User user) {
super(source);
this.user = user;
}
public User getUser() {
return user;
}
}
Event publishen:
@Service
@RequiredArgsConstructor
public class UserService {
private final ApplicationEventPublisher eventPublisher;
public User registerUser(UserDTO dto) {
User user = userRepository.save(dto.toEntity());
// Event publishen
eventPublisher.publishEvent(new UserRegisteredEvent(this, user));
return user;
}
}
Event Listener:
@Component
@RequiredArgsConstructor
public class UserEventListener {
private final EmailService emailService;
@EventListener
@Async
public void handleUserRegistered(UserRegisteredEvent event) {
emailService.sendWelcomeEmail(event.getUser());
}
}
Vergleich:
| Feature | Spring Events | JMS |
|---|---|---|
| Persistence | ❌ Nein | ✅ Ja |
| Retry | ❌ Manuell | ✅ Automatisch |
| Microservices | ❌ Nein | ✅ Ja |
| Performance | ⚡ Sehr schnell | 🐢 Langsamer |
| Komplexität | ✅ Einfach | ⚠️ Komplexer |
Wann was?
- Spring Events: Single App, einfache Events, Performance wichtig
- JMS: Microservices, Persistence wichtig, Retry nötig
🔵 BONUS – Abschluss
Du hast gesehen:
- JMS für persistent Messages
- Batch-Email für Performance
- Spring Events als leichtgewichtige Alternative
Wichtig: Das musst du NICHT jetzt alles können! Komm zurück zu diesem Teil, wenn du:
- Microservices baust
- Newsletter-Funktion implementierst
- Event-Driven Architecture verstehen willst
Nimm mit: Es gibt mehrere Wege, Messages zu versenden. Je nach Use-Case den richtigen wählen!
📥 Downloads & Materialien
Für diesen Tag:
- 📦 Starter-Projekt – Ausgangsbasis
- 📦 Finales Projekt – Komplette Lösung
- 📄 Cheat Sheet – Alle Befehle
- 📝 Übungsaufgaben – Zum Festigen
Weiterführend:
GitHub-Repository: 👉 tag7-spring-boot-messaging-email
✅ Checkpoint: Hast du Tag 7 geschafft?
Kontrolliere deine Erfolge:
🟢 Grundlagen (PFLICHT):
- [ ] MailDev läuft und funktioniert
- [ ] Erste simple Email versendet
- [ ] HTML-Email mit Thymeleaf Template erstellt
- [ ] Template-Variablen funktionieren
- [ ] Email wird in MailDev angezeigt
🟡 Professionals (EMPFOHLEN):
- [ ] @Async Email-Versand implementiert
- [ ] Response-Zeit deutlich verbessert (< 500ms)
- [ ] Error-Handling eingebaut
- [ ] Thread Pool konfiguriert
- [ ] User-Registrierung mit async Email funktioniert
🔵 Bonus (OPTIONAL):
- [ ] JMS ausprobiert
- [ ] Spring Events verstanden
- [ ] Vergleich @Async vs JMS vs Events
✅ Alle Grundlagen-Häkchen gesetzt?
Glückwunsch! Du bist bereit für Tag 8! 🎉
❌ Nicht alles funktioniert?
Kein Problem! Schau nochmal in:
- Die Grundlagen-Schritte 1-9
- Die Troubleshooting-Sektion
- Das finale Projekt zum Vergleichen
Brauchst du mehr Zeit?
Nimm dir die Zeit! Qualität vor Geschwindigkeit. 💪
Besser Tag 7 richtig verstanden, als halbfertig zu Tag 8!
❓ FAQ (Häufige Fragen)
Q: Ich komme bei Schritt 5 nicht weiter – Email wird nicht versendet!
A: Checke: (1) MailDev läuft? docker ps. (2) application.properties korrekt? (3) Port 1025 frei? (4) Logs in Console prüfen!
Q: Wie lange sollte ich für diesen Tag brauchen?
A: Ca. 8 Stunden mit Pausen. Grundlagen: 4h, Professionals: 3h, Bonus: 1h. Wenn du länger brauchst – kein Problem!
Q: Muss ich die Bonus-Sektion machen?
A: Nein! Bonus ist optional. Fokussiere dich auf Grundlagen & Professionals. Bonus kannst du später nachholen!
Q: @Async funktioniert nicht – was tun?
A: (1) @EnableAsync in Main-Klasse? (2) Methode ist public? (3) Methode wird von anderer Klasse aufgerufen (nicht this.asyncMethod())?
Q: Gmail statt MailDev – wie?
A: Nicht empfohlen für Development! Aber möglich: (1) Gmail App-Passwort erstellen, (2) application.properties anpassen (siehe Projekt-README), (3) SMTP-Port 587.
Q: Wann @Async und wann JMS?
A: @Async: Einfache Tasks, Single App, Performance wichtig. JMS: Microservices, Persistence wichtig, Retry nötig.
Q: Kann ich mehrere Email-Templates haben?
A: Ja! Erstelle einfach mehrere .html Dateien in /templates/email/. Z.B.: welcome.html, password-reset.html, order-confirmation.html.
Q: Was macht ihr eigentlich bei emotionalen Problemen im Team?
A: Gute Frage… Manche Geschichten passen nicht in Tech-Blogs. Die gehören eher zu… wie sagt Nova immer? Herz Schmerz und private logs. Aber das ist ein anderes Kapitel. 📖
Q: Wie teste ich Email-Versand?
A: Am besten mit MailDev! Alternativ: Spring Mail Test Support mit @MockBean(JavaMailSender.class) in Unit-Tests.
🔥 Elyndras Real Talk
Mein Email-Horror:
Vor 3 Jahren hab ich eine Newsletter-Funktion gebaut. Synchroner Versand an 1000 User. Die Queue lief voll, der Server crashed nach 5 Minuten. Franz war… not amused. 😅
Was war falsch?
- ❌ Kein @Async
- ❌ Kein Thread Pool Limit
- ❌ Kein Error-Handling
- ❌ Keine Retry-Logic
Die Lektion:
- ✅ IMMER async bei Email-Versand
- ✅ IMMER Thread Pool konfigurieren
- ✅ IMMER Error-Handling
- ✅ Bei wichtigen Emails: JMS mit Dead Letter Queue
Nova kam zu mir:
„Elyndra, warum dauert meine User-Registrierung 5 Sekunden?“
Ich schaute in ihren Code… synchroner Email-Versand. Classic Rookie-Mistake!
„Nova, schau: Der User wartet, bis die Email raus ist. Mach’s async – der User bekommt sofort Response, die Email läuft im Hintergrund.“
Sie probierte es aus: 5 Sekunden → 200ms. Ihr Gesicht war unbezahlbar! 😄
Was ich heute empfehle:
Development:
- MailDev + @Async (einfach, schnell, gut)
- Spring Events für interne Communication
Production:
- Real SMTP (SendGrid, AWS SES, etc.)
- JMS für kritische Emails (Bestellbestätigungen)
- Dead Letter Queue für Failed Messages
- Monitoring mit Spring Boot Actuator
Der wichtigste Tipp: Email-Versand kann fehlschlagen. Plan for failure! Error-Handling, Retry-Logic, Monitoring.
Kofi sagte letztens:
„Email ist wie Briefpost. Manchmal kommt der Brief an, manchmal nicht. Wichtig ist: Der Postbote (deine App) darf nicht hängenbleiben, wenn ein Brief nicht rausgeht.“
Besser kann man es nicht sagen! 📧
🗺️ Deine nächsten Schritte
✅ Du hast Tag 7 geschafft! Was jetzt?
Nächster Tag:
- 📜 Tag 8: Testing & Dokumentation
- Unit Testing mit JUnit 5 & Mockito
- Integration Testing mit @SpringBootTest
- API-Dokumentation mit OpenAPI/Swagger
- Test-Driven Development (TDD)
- 📅 Veröffentlicht: Morgen
- ⏱️ Dauer: 8 Stunden
Vorbereitung für Tag 8:
- [ ] Tag 7 Grundlagen vollständig ✅
- [ ] @Async Email-Versand verstanden
- [ ] Email-Service funktioniert
- [ ] Projekt läuft ohne Fehler
Noch nicht bereit?
Kein Problem! Arbeite Tag 7 nochmal nach. Testing macht erst Sinn, wenn du Email-Versand verstanden hast. Qualität vor Tempo! 💪
Alle Blogbeiträge dieser Serie:
👉 Spring Boot Aufbau – Komplette Übersicht
Das war Tag 7 von Spring Boot Aufbau!
Du kannst jetzt:
- ✅ Emails mit Spring Boot Mail versenden
- ✅ HTML-Templates mit Thymeleaf erstellen
- ✅ Asynchronen Email-Versand für bessere Performance
- ✅ Den Unterschied zwischen @Async, JMS und Spring Events
- ✅ Production-ready Email-Services bauen
Morgen lernst du Testing & Dokumentation! 🚀
Keep coding, keep learning! 💙
Tag 8 erscheint morgen. Bis dahin: Happy Coding!
P.S.: Manchmal verstecken sich die interessantesten Geschichten nicht in Code-Repositories, sondern in den… nun ja, private logs. Probier mal die Suche oben auf java-developer.online! 😉
Tags: #SpringBoot #Email #Messaging #JMS #Async #Tag7 #Kurs

