Implements a comprehensive email system with: - Multi-provider support (SMTP, SendGrid, Mailgun, Amazon SES) - Database-stored templates with i18n (EN, FR, DE, LB) - Jinja2 template rendering with variable interpolation - Email logging for debugging and compliance - Debug mode for development (logs instead of sending) - Welcome email integration in signup flow New files: - models/database/email.py: EmailTemplate and EmailLog models - app/services/email_service.py: Provider abstraction and service - scripts/seed_email_templates.py: Template seeding script - tests/unit/services/test_email_service.py: 28 unit tests - docs/features/email-system.md: Complete documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
419 lines
16 KiB
Python
419 lines
16 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Seed default email templates.
|
|
|
|
Run: python scripts/seed_email_templates.py
|
|
"""
|
|
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Add project root to path
|
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
|
|
from app.core.database import get_db
|
|
from models.database.email import EmailCategory, EmailTemplate
|
|
|
|
|
|
# =============================================================================
|
|
# EMAIL TEMPLATES
|
|
# =============================================================================
|
|
|
|
TEMPLATES = [
|
|
# -------------------------------------------------------------------------
|
|
# SIGNUP WELCOME
|
|
# -------------------------------------------------------------------------
|
|
{
|
|
"code": "signup_welcome",
|
|
"language": "en",
|
|
"name": "Signup Welcome",
|
|
"description": "Sent to new vendors after successful signup",
|
|
"category": EmailCategory.AUTH.value,
|
|
"variables": json.dumps([
|
|
"first_name", "company_name", "email", "vendor_code",
|
|
"login_url", "trial_days", "tier_name"
|
|
]),
|
|
"subject": "Welcome to Wizamart, {{ first_name }}!",
|
|
"body_html": """<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
</head>
|
|
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
|
|
<div style="background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); padding: 30px; border-radius: 10px 10px 0 0;">
|
|
<h1 style="color: white; margin: 0; font-size: 28px;">Welcome to Wizamart!</h1>
|
|
</div>
|
|
|
|
<div style="background: #f9fafb; padding: 30px; border-radius: 0 0 10px 10px;">
|
|
<p style="font-size: 16px;">Hi {{ first_name }},</p>
|
|
|
|
<p>Thank you for signing up for Wizamart! Your account for <strong>{{ company_name }}</strong> is now active.</p>
|
|
|
|
<div style="background: white; border-radius: 8px; padding: 20px; margin: 20px 0; border-left: 4px solid #6366f1;">
|
|
<h3 style="margin-top: 0; color: #6366f1;">Your Account Details</h3>
|
|
<p style="margin: 5px 0;"><strong>Vendor Code:</strong> {{ vendor_code }}</p>
|
|
<p style="margin: 5px 0;"><strong>Plan:</strong> {{ tier_name }}</p>
|
|
<p style="margin: 5px 0;"><strong>Trial Period:</strong> {{ trial_days }} days free</p>
|
|
</div>
|
|
|
|
<p>You can start managing your orders, inventory, and invoices right away:</p>
|
|
|
|
<div style="text-align: center; margin: 30px 0;">
|
|
<a href="{{ login_url }}" style="background: #6366f1; color: white; padding: 14px 28px; text-decoration: none; border-radius: 8px; font-weight: bold; display: inline-block;">
|
|
Go to Dashboard
|
|
</a>
|
|
</div>
|
|
|
|
<h3 style="color: #374151;">Getting Started</h3>
|
|
<ol style="color: #4b5563;">
|
|
<li>Complete your company profile</li>
|
|
<li>Connect your Letzshop API credentials</li>
|
|
<li>Import your products</li>
|
|
<li>Start syncing orders!</li>
|
|
</ol>
|
|
|
|
<p style="color: #6b7280; font-size: 14px; margin-top: 30px;">
|
|
If you have any questions, just reply to this email or visit our help center.
|
|
</p>
|
|
|
|
<p>Best regards,<br><strong>The Wizamart Team</strong></p>
|
|
</div>
|
|
|
|
<div style="text-align: center; padding: 20px; color: #9ca3af; font-size: 12px;">
|
|
<p>© 2024 Wizamart. Built for Luxembourg e-commerce.</p>
|
|
</div>
|
|
</body>
|
|
</html>""",
|
|
"body_text": """Welcome to Wizamart!
|
|
|
|
Hi {{ first_name }},
|
|
|
|
Thank you for signing up for Wizamart! Your account for {{ company_name }} is now active.
|
|
|
|
Your Account Details:
|
|
- Vendor Code: {{ vendor_code }}
|
|
- Plan: {{ tier_name }}
|
|
- Trial Period: {{ trial_days }} days free
|
|
|
|
You can start managing your orders, inventory, and invoices right away.
|
|
|
|
Go to Dashboard: {{ login_url }}
|
|
|
|
Getting Started:
|
|
1. Complete your company profile
|
|
2. Connect your Letzshop API credentials
|
|
3. Import your products
|
|
4. Start syncing orders!
|
|
|
|
If you have any questions, just reply to this email.
|
|
|
|
Best regards,
|
|
The Wizamart Team
|
|
""",
|
|
},
|
|
{
|
|
"code": "signup_welcome",
|
|
"language": "fr",
|
|
"name": "Bienvenue après inscription",
|
|
"description": "Envoyé aux nouveaux vendeurs après inscription",
|
|
"category": EmailCategory.AUTH.value,
|
|
"variables": json.dumps([
|
|
"first_name", "company_name", "email", "vendor_code",
|
|
"login_url", "trial_days", "tier_name"
|
|
]),
|
|
"subject": "Bienvenue sur Wizamart, {{ first_name }} !",
|
|
"body_html": """<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
</head>
|
|
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
|
|
<div style="background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); padding: 30px; border-radius: 10px 10px 0 0;">
|
|
<h1 style="color: white; margin: 0; font-size: 28px;">Bienvenue sur Wizamart !</h1>
|
|
</div>
|
|
|
|
<div style="background: #f9fafb; padding: 30px; border-radius: 0 0 10px 10px;">
|
|
<p style="font-size: 16px;">Bonjour {{ first_name }},</p>
|
|
|
|
<p>Merci de vous être inscrit sur Wizamart ! Votre compte pour <strong>{{ company_name }}</strong> est maintenant actif.</p>
|
|
|
|
<div style="background: white; border-radius: 8px; padding: 20px; margin: 20px 0; border-left: 4px solid #6366f1;">
|
|
<h3 style="margin-top: 0; color: #6366f1;">Détails de votre compte</h3>
|
|
<p style="margin: 5px 0;"><strong>Code vendeur :</strong> {{ vendor_code }}</p>
|
|
<p style="margin: 5px 0;"><strong>Forfait :</strong> {{ tier_name }}</p>
|
|
<p style="margin: 5px 0;"><strong>Période d'essai :</strong> {{ trial_days }} jours gratuits</p>
|
|
</div>
|
|
|
|
<p>Vous pouvez commencer à gérer vos commandes, stocks et factures dès maintenant :</p>
|
|
|
|
<div style="text-align: center; margin: 30px 0;">
|
|
<a href="{{ login_url }}" style="background: #6366f1; color: white; padding: 14px 28px; text-decoration: none; border-radius: 8px; font-weight: bold; display: inline-block;">
|
|
Accéder au tableau de bord
|
|
</a>
|
|
</div>
|
|
|
|
<h3 style="color: #374151;">Pour commencer</h3>
|
|
<ol style="color: #4b5563;">
|
|
<li>Complétez votre profil d'entreprise</li>
|
|
<li>Connectez vos identifiants API Letzshop</li>
|
|
<li>Importez vos produits</li>
|
|
<li>Commencez à synchroniser vos commandes !</li>
|
|
</ol>
|
|
|
|
<p style="color: #6b7280; font-size: 14px; margin-top: 30px;">
|
|
Si vous avez des questions, répondez simplement à cet email.
|
|
</p>
|
|
|
|
<p>Cordialement,<br><strong>L'équipe Wizamart</strong></p>
|
|
</div>
|
|
|
|
<div style="text-align: center; padding: 20px; color: #9ca3af; font-size: 12px;">
|
|
<p>© 2024 Wizamart. Conçu pour le e-commerce luxembourgeois.</p>
|
|
</div>
|
|
</body>
|
|
</html>""",
|
|
"body_text": """Bienvenue sur Wizamart !
|
|
|
|
Bonjour {{ first_name }},
|
|
|
|
Merci de vous être inscrit sur Wizamart ! Votre compte pour {{ company_name }} est maintenant actif.
|
|
|
|
Détails de votre compte :
|
|
- Code vendeur : {{ vendor_code }}
|
|
- Forfait : {{ tier_name }}
|
|
- Période d'essai : {{ trial_days }} jours gratuits
|
|
|
|
Accéder au tableau de bord : {{ login_url }}
|
|
|
|
Pour commencer :
|
|
1. Complétez votre profil d'entreprise
|
|
2. Connectez vos identifiants API Letzshop
|
|
3. Importez vos produits
|
|
4. Commencez à synchroniser vos commandes !
|
|
|
|
Cordialement,
|
|
L'équipe Wizamart
|
|
""",
|
|
},
|
|
{
|
|
"code": "signup_welcome",
|
|
"language": "de",
|
|
"name": "Willkommen nach Anmeldung",
|
|
"description": "An neue Verkäufer nach erfolgreicher Anmeldung gesendet",
|
|
"category": EmailCategory.AUTH.value,
|
|
"variables": json.dumps([
|
|
"first_name", "company_name", "email", "vendor_code",
|
|
"login_url", "trial_days", "tier_name"
|
|
]),
|
|
"subject": "Willkommen bei Wizamart, {{ first_name }}!",
|
|
"body_html": """<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
</head>
|
|
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
|
|
<div style="background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); padding: 30px; border-radius: 10px 10px 0 0;">
|
|
<h1 style="color: white; margin: 0; font-size: 28px;">Willkommen bei Wizamart!</h1>
|
|
</div>
|
|
|
|
<div style="background: #f9fafb; padding: 30px; border-radius: 0 0 10px 10px;">
|
|
<p style="font-size: 16px;">Hallo {{ first_name }},</p>
|
|
|
|
<p>Vielen Dank für Ihre Anmeldung bei Wizamart! Ihr Konto für <strong>{{ company_name }}</strong> ist jetzt aktiv.</p>
|
|
|
|
<div style="background: white; border-radius: 8px; padding: 20px; margin: 20px 0; border-left: 4px solid #6366f1;">
|
|
<h3 style="margin-top: 0; color: #6366f1;">Ihre Kontodaten</h3>
|
|
<p style="margin: 5px 0;"><strong>Verkäufercode:</strong> {{ vendor_code }}</p>
|
|
<p style="margin: 5px 0;"><strong>Tarif:</strong> {{ tier_name }}</p>
|
|
<p style="margin: 5px 0;"><strong>Testzeitraum:</strong> {{ trial_days }} Tage kostenlos</p>
|
|
</div>
|
|
|
|
<p>Sie können sofort mit der Verwaltung Ihrer Bestellungen, Bestände und Rechnungen beginnen:</p>
|
|
|
|
<div style="text-align: center; margin: 30px 0;">
|
|
<a href="{{ login_url }}" style="background: #6366f1; color: white; padding: 14px 28px; text-decoration: none; border-radius: 8px; font-weight: bold; display: inline-block;">
|
|
Zum Dashboard
|
|
</a>
|
|
</div>
|
|
|
|
<h3 style="color: #374151;">Erste Schritte</h3>
|
|
<ol style="color: #4b5563;">
|
|
<li>Vervollständigen Sie Ihr Firmenprofil</li>
|
|
<li>Verbinden Sie Ihre Letzshop API-Zugangsdaten</li>
|
|
<li>Importieren Sie Ihre Produkte</li>
|
|
<li>Starten Sie die Bestellungssynchronisierung!</li>
|
|
</ol>
|
|
|
|
<p style="color: #6b7280; font-size: 14px; margin-top: 30px;">
|
|
Bei Fragen antworten Sie einfach auf diese E-Mail.
|
|
</p>
|
|
|
|
<p>Mit freundlichen Grüßen,<br><strong>Das Wizamart-Team</strong></p>
|
|
</div>
|
|
|
|
<div style="text-align: center; padding: 20px; color: #9ca3af; font-size: 12px;">
|
|
<p>© 2024 Wizamart. Entwickelt für den luxemburgischen E-Commerce.</p>
|
|
</div>
|
|
</body>
|
|
</html>""",
|
|
"body_text": """Willkommen bei Wizamart!
|
|
|
|
Hallo {{ first_name }},
|
|
|
|
Vielen Dank für Ihre Anmeldung bei Wizamart! Ihr Konto für {{ company_name }} ist jetzt aktiv.
|
|
|
|
Ihre Kontodaten:
|
|
- Verkäufercode: {{ vendor_code }}
|
|
- Tarif: {{ tier_name }}
|
|
- Testzeitraum: {{ trial_days }} Tage kostenlos
|
|
|
|
Zum Dashboard: {{ login_url }}
|
|
|
|
Erste Schritte:
|
|
1. Vervollständigen Sie Ihr Firmenprofil
|
|
2. Verbinden Sie Ihre Letzshop API-Zugangsdaten
|
|
3. Importieren Sie Ihre Produkte
|
|
4. Starten Sie die Bestellungssynchronisierung!
|
|
|
|
Mit freundlichen Grüßen,
|
|
Das Wizamart-Team
|
|
""",
|
|
},
|
|
{
|
|
"code": "signup_welcome",
|
|
"language": "lb",
|
|
"name": "Wëllkomm no der Umeldung",
|
|
"description": "Un nei Verkeefer no erfollegräicher Umeldung geschéckt",
|
|
"category": EmailCategory.AUTH.value,
|
|
"variables": json.dumps([
|
|
"first_name", "company_name", "email", "vendor_code",
|
|
"login_url", "trial_days", "tier_name"
|
|
]),
|
|
"subject": "Wëllkomm op Wizamart, {{ first_name }}!",
|
|
"body_html": """<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
</head>
|
|
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
|
|
<div style="background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); padding: 30px; border-radius: 10px 10px 0 0;">
|
|
<h1 style="color: white; margin: 0; font-size: 28px;">Wëllkomm op Wizamart!</h1>
|
|
</div>
|
|
|
|
<div style="background: #f9fafb; padding: 30px; border-radius: 0 0 10px 10px;">
|
|
<p style="font-size: 16px;">Moien {{ first_name }},</p>
|
|
|
|
<p>Merci fir d'Umeldung op Wizamart! Äre Kont fir <strong>{{ company_name }}</strong> ass elo aktiv.</p>
|
|
|
|
<div style="background: white; border-radius: 8px; padding: 20px; margin: 20px 0; border-left: 4px solid #6366f1;">
|
|
<h3 style="margin-top: 0; color: #6366f1;">Är Kontdetailer</h3>
|
|
<p style="margin: 5px 0;"><strong>Verkeefer Code:</strong> {{ vendor_code }}</p>
|
|
<p style="margin: 5px 0;"><strong>Plang:</strong> {{ tier_name }}</p>
|
|
<p style="margin: 5px 0;"><strong>Testperiod:</strong> {{ trial_days }} Deeg gratis</p>
|
|
</div>
|
|
|
|
<p>Dir kënnt direkt ufänken Är Bestellungen, Lager a Rechnungen ze verwalten:</p>
|
|
|
|
<div style="text-align: center; margin: 30px 0;">
|
|
<a href="{{ login_url }}" style="background: #6366f1; color: white; padding: 14px 28px; text-decoration: none; border-radius: 8px; font-weight: bold; display: inline-block;">
|
|
Zum Dashboard
|
|
</a>
|
|
</div>
|
|
|
|
<h3 style="color: #374151;">Fir unzefänken</h3>
|
|
<ol style="color: #4b5563;">
|
|
<li>Fëllt Äre Firmeprofil aus</li>
|
|
<li>Verbindt Är Letzshop API Zougangsdaten</li>
|
|
<li>Importéiert Är Produkter</li>
|
|
<li>Fänkt un Bestellungen ze synchroniséieren!</li>
|
|
</ol>
|
|
|
|
<p style="color: #6b7280; font-size: 14px; margin-top: 30px;">
|
|
Wann Dir Froen hutt, äntwert einfach op dës E-Mail.
|
|
</p>
|
|
|
|
<p>Mat beschte Gréiss,<br><strong>D'Wizamart Team</strong></p>
|
|
</div>
|
|
|
|
<div style="text-align: center; padding: 20px; color: #9ca3af; font-size: 12px;">
|
|
<p>© 2024 Wizamart. Gemaach fir de lëtzebuergeschen E-Commerce.</p>
|
|
</div>
|
|
</body>
|
|
</html>""",
|
|
"body_text": """Wëllkomm op Wizamart!
|
|
|
|
Moien {{ first_name }},
|
|
|
|
Merci fir d'Umeldung op Wizamart! Äre Kont fir {{ company_name }} ass elo aktiv.
|
|
|
|
Är Kontdetailer:
|
|
- Verkeefer Code: {{ vendor_code }}
|
|
- Plang: {{ tier_name }}
|
|
- Testperiod: {{ trial_days }} Deeg gratis
|
|
|
|
Zum Dashboard: {{ login_url }}
|
|
|
|
Fir unzefänken:
|
|
1. Fëllt Äre Firmeprofil aus
|
|
2. Verbindt Är Letzshop API Zougangsdaten
|
|
3. Importéiert Är Produkter
|
|
4. Fänkt un Bestellungen ze synchroniséieren!
|
|
|
|
Mat beschte Gréiss,
|
|
D'Wizamart Team
|
|
""",
|
|
},
|
|
]
|
|
|
|
|
|
def seed_templates():
|
|
"""Seed email templates into database."""
|
|
db = next(get_db())
|
|
|
|
try:
|
|
created = 0
|
|
updated = 0
|
|
|
|
for template_data in TEMPLATES:
|
|
# Check if template already exists
|
|
existing = (
|
|
db.query(EmailTemplate)
|
|
.filter(
|
|
EmailTemplate.code == template_data["code"],
|
|
EmailTemplate.language == template_data["language"],
|
|
)
|
|
.first()
|
|
)
|
|
|
|
if existing:
|
|
# Update existing template
|
|
for key, value in template_data.items():
|
|
setattr(existing, key, value)
|
|
updated += 1
|
|
print(f"Updated: {template_data['code']} ({template_data['language']})")
|
|
else:
|
|
# Create new template
|
|
template = EmailTemplate(**template_data)
|
|
db.add(template)
|
|
created += 1
|
|
print(f"Created: {template_data['code']} ({template_data['language']})")
|
|
|
|
db.commit()
|
|
print(f"\nDone! Created: {created}, Updated: {updated}")
|
|
|
|
except Exception as e:
|
|
db.rollback()
|
|
print(f"Error: {e}")
|
|
raise
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
seed_templates()
|