Versions stable (inachevée mais prête à un déploiement en prod)
This commit is contained in:
201
src/main/java/dev/lions/services/EmailService.java
Normal file
201
src/main/java/dev/lions/services/EmailService.java
Normal file
@@ -0,0 +1,201 @@
|
||||
package dev.lions.services;
|
||||
|
||||
import dev.lions.models.EmailMessage;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.mail.Message;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.Session;
|
||||
import jakarta.mail.Transport;
|
||||
import jakarta.mail.internet.InternetAddress;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import dev.lions.config.ApplicationConfig;
|
||||
import dev.lions.models.EmailTemplate;
|
||||
import dev.lions.models.Notification;
|
||||
import dev.lions.exceptions.EmailException;
|
||||
import dev.lions.utils.TemplateProcessor;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Service gérant l'envoi des emails dans l'application.
|
||||
* Cette classe assure la configuration SMTP, le traitement des modèles
|
||||
* et l'envoi sécurisé des emails.
|
||||
*/
|
||||
@Slf4j
|
||||
@ApplicationScoped
|
||||
public class EmailService {
|
||||
|
||||
@Inject
|
||||
ApplicationConfig config;
|
||||
|
||||
@Inject
|
||||
TemplateProcessor templateProcessor;
|
||||
|
||||
private static final int MAX_RETRY_ATTEMPTS = 3;
|
||||
private static final long RETRY_DELAY_MS = 1000;
|
||||
|
||||
/**
|
||||
* Envoie un email basé sur un modèle.
|
||||
*
|
||||
* @param template Modèle d'email à utiliser
|
||||
*/
|
||||
public void sendTemplatedEmail(@Valid @NotNull EmailTemplate template) {
|
||||
log.info("Préparation de l'envoi d'email avec le modèle : {}",
|
||||
template.getTemplateName());
|
||||
|
||||
try {
|
||||
String htmlContent = processTemplate(template);
|
||||
|
||||
EmailMessage message = EmailMessage.builder()
|
||||
.from(config.getSystemEmailAddress())
|
||||
.to(template.getRecipient())
|
||||
.subject(template.getSubject())
|
||||
.htmlContent(htmlContent)
|
||||
.build();
|
||||
|
||||
sendEmailWithRetry(message);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Erreur lors de l'envoi de l'email", e);
|
||||
throw new EmailException("Impossible d'envoyer l'email");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Traite le contenu du modèle avec les paramètres fournis.
|
||||
*/
|
||||
private String processTemplate(EmailTemplate template) {
|
||||
log.debug("Traitement du modèle d'email : {}", template.getTemplateName());
|
||||
return templateProcessor.process(
|
||||
template.getContent(),
|
||||
template.getParameters()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Envoie un email avec mécanisme de reprise en cas d'échec.
|
||||
*/
|
||||
private void sendEmailWithRetry(EmailMessage message) {
|
||||
Exception lastException = null;
|
||||
|
||||
for (int attempt = 1; attempt <= MAX_RETRY_ATTEMPTS; attempt++) {
|
||||
try {
|
||||
sendEmail(message);
|
||||
log.info("Email envoyé avec succès à : {}", message.getTo());
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
lastException = e;
|
||||
log.warn("Échec de l'envoi (tentative {}/{})",
|
||||
attempt, MAX_RETRY_ATTEMPTS);
|
||||
|
||||
if (attempt < MAX_RETRY_ATTEMPTS) {
|
||||
sleep(RETRY_DELAY_MS * attempt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new EmailException(
|
||||
"Échec de l'envoi après " + MAX_RETRY_ATTEMPTS + " tentatives");
|
||||
}
|
||||
|
||||
/**
|
||||
* Envoie effectif de l'email via SMTP.
|
||||
*/
|
||||
private void sendEmail(EmailMessage message) throws MessagingException {
|
||||
Properties props = configureSmtpProperties();
|
||||
Session session = createSmtpSession(props);
|
||||
|
||||
MimeMessage mimeMessage = new MimeMessage(session);
|
||||
configureMimeMessage(mimeMessage, message);
|
||||
|
||||
Transport.send(mimeMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure les propriétés SMTP.
|
||||
*/
|
||||
private Properties configureSmtpProperties() {
|
||||
Properties props = new Properties();
|
||||
props.put("mail.smtp.host", config.getSmtpHost());
|
||||
props.put("mail.smtp.port", config.getSmtpPort());
|
||||
props.put("mail.smtp.auth", "true");
|
||||
props.put("mail.smtp.starttls.enable", "true");
|
||||
props.put("mail.smtp.connectiontimeout", "5000");
|
||||
props.put("mail.smtp.timeout", "5000");
|
||||
|
||||
if (config.isSmtpSslEnabled()) {
|
||||
props.put("mail.smtp.ssl.enable", "true");
|
||||
props.put("mail.smtp.ssl.trust", config.getSmtpHost());
|
||||
}
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée une session SMTP authentifiée.
|
||||
*/
|
||||
private Session createSmtpSession(Properties props) {
|
||||
return Session.getInstance(props, new jakarta.mail.Authenticator() {
|
||||
@Override
|
||||
protected jakarta.mail.PasswordAuthentication getPasswordAuthentication() {
|
||||
return new jakarta.mail.PasswordAuthentication(
|
||||
config.getSmtpUsername().orElseThrow(() ->
|
||||
new EmailException("Nom d'utilisateur SMTP manquant")),
|
||||
config.getSmtpPassword().orElseThrow(() ->
|
||||
new EmailException("Mot de passe SMTP manquant"))
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure le message MIME avec les paramètres fournis.
|
||||
*/
|
||||
private void configureMimeMessage(MimeMessage mimeMessage, EmailMessage message)
|
||||
throws MessagingException {
|
||||
mimeMessage.setFrom(new InternetAddress(message.getFrom()));
|
||||
mimeMessage.setRecipients(
|
||||
Message.RecipientType.TO,
|
||||
InternetAddress.parse(message.getTo())
|
||||
);
|
||||
mimeMessage.setSubject(message.getSubject());
|
||||
mimeMessage.setContent(message.getHtmlContent(), "text/html; charset=utf-8");
|
||||
}
|
||||
|
||||
/**
|
||||
* Envoie une notification par email.
|
||||
*/
|
||||
public void sendNotificationEmail(@NotNull Notification notification) {
|
||||
EmailTemplate template = EmailTemplate.builder()
|
||||
.templateName("notification-email")
|
||||
.recipient(config.getAdminEmailAddress())
|
||||
.subject("Notification système : " + notification.getTitle())
|
||||
.parameters(Map.of(
|
||||
"title", notification.getTitle(),
|
||||
"message", notification.getMessage(),
|
||||
"type", notification.getType().toString(),
|
||||
"timestamp", notification.getTimestamp().toString(),
|
||||
"actionUrl", notification.getActionUrl()
|
||||
))
|
||||
.build();
|
||||
|
||||
sendTemplatedEmail(template);
|
||||
}
|
||||
|
||||
private void sleep(long milliseconds) {
|
||||
try {
|
||||
Thread.sleep(milliseconds);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new EmailException("Interruption pendant la reprise");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user