feat: redesign newsletter email with modern template

- Redesign email template with brand colors and modern layout
- Add animated welcome icon and professional styling
- Improve button design with gradient colors matching the site
- Add TLS configuration to fix SSL certificate errors
- Fix email validation regex to be more permissive
- Update email subject to include logo emoji

Design improvements:
- Logo in header with brand colors (#d4a574, #c4956a, #5a5a4e)
- Beautiful rounded buttons for "Jouer Maintenant" and "Visiter le Site"
- Responsive design with proper spacing and shadows
- Benefits section with visual icons
- Professional footer with unsubscribe link

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
soufiane 2025-11-24 14:49:40 +01:00
parent 772202dc6e
commit 0850614264
2 changed files with 364 additions and 36 deletions

View File

@ -21,6 +21,9 @@ const createTransporter = () => {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS,
},
tls: {
rejectUnauthorized: false // Ignore les erreurs de certificat SSL
}
});
};
@ -61,45 +64,351 @@ const sendEmail = async ({ to, subject, html, text }) => {
*/
export const sendNewsletterConfirmationEmail = async (email) => {
const unsubscribeUrl = `${process.env.FRONTEND_URL || 'http://localhost:3000'}/newsletter/unsubscribe?email=${encodeURIComponent(email)}`;
const siteUrl = process.env.FRONTEND_URL || 'http://localhost:3000';
const gameUrl = `${siteUrl}/game`;
const currentDate = new Date().toLocaleString('fr-FR', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
const html = `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
.header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; text-align: center; border-radius: 10px 10px 0 0; }
.content { background: #f9f9f9; padding: 30px; border-radius: 0 0 10px 10px; }
.footer { text-align: center; margin-top: 20px; color: #666; font-size: 12px; }
.unsubscribe { margin-top: 30px; padding-top: 20px; border-top: 1px solid #ddd; }
.unsubscribe a { color: #999; text-decoration: none; }
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: #5a5a4e;
margin: 0;
padding: 0;
background: linear-gradient(135deg, #f5f5f0 0%, #faf9f5 100%);
}
.email-wrapper {
padding: 40px 20px;
}
.container {
max-width: 650px;
margin: 0 auto;
background: white;
border-radius: 20px;
overflow: hidden;
box-shadow: 0 10px 40px rgba(0,0,0,0.15);
}
.header {
background: linear-gradient(135deg, #d4a574 0%, #c4956a 100%);
color: white;
padding: 50px 30px;
text-align: center;
position: relative;
}
.logo-container {
display: flex;
align-items: center;
justify-content: center;
gap: 15px;
margin-bottom: 15px;
}
.logo-icon {
font-size: 48px;
filter: drop-shadow(0 2px 4px rgba(0,0,0,0.2));
}
.logo-text {
font-size: 36px;
font-weight: bold;
letter-spacing: 1px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.2);
}
.header-subtitle {
font-size: 16px;
opacity: 0.95;
letter-spacing: 2px;
text-transform: uppercase;
font-weight: 500;
}
.welcome-section {
background: linear-gradient(135deg, #d4a574 0%, #c4956a 100%);
color: white;
padding: 40px 30px;
text-align: center;
border-bottom: 4px solid rgba(255,255,255,0.2);
}
.welcome-icon {
font-size: 60px;
margin-bottom: 20px;
animation: bounce 2s infinite;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
.welcome-title {
font-size: 32px;
font-weight: bold;
margin: 15px 0;
text-shadow: 2px 2px 4px rgba(0,0,0,0.2);
}
.user-info {
background: rgba(255,255,255,0.15);
backdrop-filter: blur(10px);
padding: 25px;
border-radius: 15px;
margin: 25px 0;
border: 1px solid rgba(255,255,255,0.3);
}
.user-info-item {
display: flex;
align-items: center;
justify-content: center;
margin: 12px 0;
font-size: 15px;
}
.content {
padding: 40px 30px;
background: linear-gradient(to bottom, #faf9f5 0%, #f5f5f0 100%);
}
.game-section {
background: white;
border: 3px solid #d4a574;
border-radius: 20px;
padding: 35px;
text-align: center;
margin: 30px 0;
box-shadow: 0 4px 15px rgba(212, 165, 116, 0.2);
}
.game-icon {
font-size: 64px;
margin-bottom: 20px;
filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1));
}
.game-title {
font-size: 28px;
color: #5a5a4e;
font-weight: bold;
margin: 20px 0;
}
.game-description {
color: #8a8a7a;
font-size: 16px;
line-height: 1.8;
margin: 20px 0;
}
.prizes-box {
background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
border-radius: 15px;
padding: 25px;
margin: 25px 0;
border-left: 5px solid #f59e0b;
}
.prizes-title {
color: #92400e;
font-size: 18px;
font-weight: bold;
margin-bottom: 10px;
}
.prizes-text {
color: #78350f;
font-size: 15px;
margin: 0;
}
.buttons-container {
margin: 30px 0;
text-align: center;
}
.button {
display: inline-block;
padding: 18px 40px;
margin: 10px 8px;
font-size: 16px;
font-weight: bold;
text-decoration: none;
border-radius: 50px;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
}
.button-primary {
background: linear-gradient(135deg, #d4a574 0%, #c4956a 100%);
color: white;
}
.button-secondary {
background: linear-gradient(135deg, #5a5a4e 0%, #4a4a42 100%);
color: white;
}
.info-box {
background: white;
border-radius: 15px;
padding: 30px;
margin: 25px 0;
box-shadow: 0 2px 10px rgba(0,0,0,0.08);
}
.info-title {
color: #5a5a4e;
font-size: 22px;
font-weight: bold;
margin-top: 0;
margin-bottom: 20px;
display: flex;
align-items: center;
gap: 10px;
}
.benefits-grid {
display: grid;
gap: 15px;
}
.benefit-item {
display: flex;
align-items: center;
padding: 15px;
background: linear-gradient(135deg, #faf9f5 0%, #f5f5f0 100%);
border-radius: 10px;
border-left: 4px solid #d4a574;
}
.benefit-icon {
font-size: 28px;
margin-right: 15px;
}
.benefit-text {
color: #5a5a4e;
font-size: 15px;
font-weight: 500;
}
.footer {
background: linear-gradient(135deg, #5a5a4e 0%, #4a4a42 100%);
color: #e5e4dc;
text-align: center;
padding: 40px 30px;
}
.footer-logo {
font-size: 24px;
margin-bottom: 10px;
}
.footer-title {
font-size: 18px;
font-weight: bold;
margin-bottom: 15px;
color: #d4a574;
}
.footer-date {
font-size: 13px;
opacity: 0.8;
margin: 15px 0;
}
.unsubscribe {
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid rgba(229, 228, 220, 0.3);
font-size: 12px;
}
.unsubscribe a {
color: #d4a574;
text-decoration: underline;
}
</style>
</head>
<body>
<div class="email-wrapper">
<div class="container">
<!-- En-tête avec Logo -->
<div class="header">
<h1>🍵 Bienvenue dans notre newsletter!</h1>
<div class="logo-container">
<div class="logo-icon">🍃</div>
<div class="logo-text">Thé Tip Top</div>
</div>
<div class="content">
<h2>Merci de votre abonnement</h2>
<p>Nous sommes ravis de vous compter parmi nos abonnés !</p>
<p>Vous recevrez désormais nos dernières actualités, offres exclusives et nouveautés directement dans votre boîte mail.</p>
<p>Restez connecté avec Thé Tip Top pour découvrir :</p>
<ul>
<li>🍵 Nos nouveaux thés et infusions</li>
<li>🎁 Des offres spéciales réservées aux abonnés</li>
<li>📰 Les actualités de nos boutiques</li>
<li>🎉 Les résultats de nos jeux-concours</li>
</ul>
<div class="unsubscribe">
<p style="font-size: 12px; color: #999;">
Vous ne souhaitez plus recevoir nos emails ? <a href="${unsubscribeUrl}">Se désabonner</a>
<div class="header-subtitle">Newsletter Jeu Concours</div>
</div>
<!-- Section Bienvenue -->
<div class="welcome-section">
<div class="welcome-icon">🎉</div>
<div class="welcome-title">Bienvenue !</div>
<p style="font-size: 18px; margin: 10px 0;">Votre inscription à la newsletter est confirmée</p>
<div class="user-info">
<div class="user-info-item">
<span style="margin-right: 10px; font-size: 20px;">📅</span>
<strong>Inscrit le ${currentDate}</strong>
</div>
</div>
<p style="font-size: 16px; margin-top: 20px; opacity: 0.95;">
Merci de rejoindre la communauté Thé Tip Top ! 🍵
</p>
</div>
<!-- Contenu principal -->
<div class="content">
<!-- Section Jeu Concours -->
<div class="game-section">
<div class="game-icon">🎯</div>
<div class="game-title">Participez à Notre Jeu Concours !</div>
<p class="game-description">
À l'occasion de l'ouverture de notre 10ème boutique à Nice,
tentez votre chance de gagner des lots exceptionnels !
</p>
<div class="prizes-box">
<div class="prizes-title">🎁 Lots à gagner</div>
<p class="prizes-text">Thés premium Accessoires Coffrets cadeaux</p>
</div>
<div class="buttons-container">
<a href="${gameUrl}" class="button button-primary">
🎮 Jouer Maintenant
</a>
<a href="${siteUrl}" class="button button-secondary">
🌐 Visiter le Site
</a>
</div>
</div>
<!-- Section Bénéfices -->
<div class="info-box">
<h3 class="info-title">
<span>📧</span>
<span>Ce que vous recevrez</span>
</h3>
<div class="benefits-grid">
<div class="benefit-item">
<span class="benefit-icon">🎮</span>
<span class="benefit-text">Nouveautés du jeu concours</span>
</div>
<div class="benefit-item">
<span class="benefit-icon">🏆</span>
<span class="benefit-text">Annonces des gagnants</span>
</div>
<div class="benefit-item">
<span class="benefit-icon">🍃</span>
<span class="benefit-text">Découvertes de thés d'exception</span>
</div>
<div class="benefit-item">
<span class="benefit-icon">🎁</span>
<span class="benefit-text">Offres exclusives réservées</span>
</div>
</div>
</div>
</div>
<!-- Pied de page -->
<div class="footer">
<p>© 2025 Thé Tip Top - Tous droits réservés</p>
<div class="footer-logo">🍃 Thé Tip Top</div>
<div class="footer-title">Votre spécialiste du thé d'exception</div>
<p class="footer-date">📧 Newsletter envoyée le ${currentDate}</p>
<div class="unsubscribe">
<p>
Vous ne souhaitez plus recevoir nos emails ?<br>
<a href="${unsubscribeUrl}">Se désinscrire</a>
</p>
</div>
<p style="margin-top: 20px; font-size: 12px; opacity: 0.7;">
© 2025 Thé Tip Top - Tous droits réservés
</p>
</div>
</div>
</div>
</body>
@ -107,20 +416,39 @@ export const sendNewsletterConfirmationEmail = async (email) => {
`;
const text = `
Bienvenue dans notre newsletter!
🍃 Thé Tip Top - Newsletter Jeu Concours
Nous sommes ravis de vous compter parmi nos abonnés !
🎉 Bienvenue Utilisateur !
Votre inscription à la newsletter est confirmée
Vous recevrez désormais nos dernières actualités, offres exclusives et nouveautés directement dans votre boîte mail.
👤 Utilisateur
📅 Inscrit le ${currentDate}
Pour vous désabonner: ${unsubscribeUrl}
🎯 Participez à Notre Jeu Concours !
À l'occasion de l'ouverture de notre 10ème boutique à Nice, tentez votre chance de gagner des lots exceptionnels !
🎁 Lots à gagner : Thés premium, accessoires, coffrets cadeaux
🎮 Jouer Maintenant : ${gameUrl}
🌐 Visiter le Site : ${siteUrl}
📧 Que recevrez-vous ?
🎮 Nouveautés du jeu concours
🏆 Annonces des gagnants
🍃 Découvertes de thés
🎁 Offres exclusives
Thé Tip Top - Votre spécialiste du thé d'exception
📧 Newsletter envoyée le ${currentDate}
Pour vous désinscrire : ${unsubscribeUrl}
© 2025 Thé Tip Top - Tous droits réservés
`;
return sendEmail({
to: email,
subject: '🍵 Bienvenue dans la newsletter Thé Tip Top',
subject: '🍃 Thé Tip Top | Bienvenue dans la newsletter - Jeu Concours 🎉',
html,
text,
});

View File

@ -10,7 +10,7 @@ export const subscribeSchema = z.object({
.string({
required_error: 'L\'email est requis',
})
.email('Format d\'email invalide'),
.regex(/^[^\s@]+@[^\s@]+\.[^\s@]+$/, 'Format d\'email invalide'),
}),
});
@ -21,7 +21,7 @@ export const unsubscribeSchema = z.object({
.string({
required_error: 'L\'email est requis',
})
.email('Format d\'email invalide'),
.regex(/^[^\s@]+@[^\s@]+\.[^\s@]+$/, 'Format d\'email invalide'),
}),
});