SMTP and other email realted settings
This commit is contained in:
@@ -27,6 +27,7 @@ class EmailSettingsAdmin(Igny8ModelAdmin):
|
||||
list_display = [
|
||||
'from_email',
|
||||
'from_name',
|
||||
'email_provider',
|
||||
'reply_to_email',
|
||||
'send_welcome_emails',
|
||||
'send_billing_emails',
|
||||
@@ -35,9 +36,26 @@ class EmailSettingsAdmin(Igny8ModelAdmin):
|
||||
readonly_fields = ['updated_at']
|
||||
|
||||
fieldsets = (
|
||||
('Email Provider', {
|
||||
'fields': ('email_provider',),
|
||||
'description': 'Select the active email service provider. Configure SMTP settings below if using SMTP.',
|
||||
}),
|
||||
('SMTP Configuration', {
|
||||
'fields': (
|
||||
'smtp_host',
|
||||
'smtp_port',
|
||||
'smtp_username',
|
||||
'smtp_password',
|
||||
'smtp_use_tls',
|
||||
'smtp_use_ssl',
|
||||
'smtp_timeout',
|
||||
),
|
||||
'description': 'SMTP server settings. Required when email_provider is set to SMTP.',
|
||||
'classes': ('collapse',),
|
||||
}),
|
||||
('Sender Configuration', {
|
||||
'fields': ('from_email', 'from_name', 'reply_to_email'),
|
||||
'description': 'Default sender settings. Email address must be verified in Resend.',
|
||||
'description': 'Default sender settings. Email address must be verified in Resend (if using Resend) or configured in SMTP server.',
|
||||
}),
|
||||
('Company Branding', {
|
||||
'fields': ('company_name', 'company_address', 'logo_url'),
|
||||
@@ -65,6 +83,114 @@ class EmailSettingsAdmin(Igny8ModelAdmin):
|
||||
}),
|
||||
)
|
||||
|
||||
change_form_template = 'admin/system/emailsettings/change_form.html'
|
||||
|
||||
def get_urls(self):
|
||||
"""Add custom URL for test email"""
|
||||
urls = super().get_urls()
|
||||
custom_urls = [
|
||||
path(
|
||||
'test-email/',
|
||||
self.admin_site.admin_view(self.test_email_view),
|
||||
name='system_emailsettings_test_email'
|
||||
),
|
||||
path(
|
||||
'send-test-email/',
|
||||
self.admin_site.admin_view(self.send_test_email),
|
||||
name='system_emailsettings_send_test'
|
||||
),
|
||||
]
|
||||
return custom_urls + urls
|
||||
|
||||
def test_email_view(self, request):
|
||||
"""Show test email form"""
|
||||
settings = EmailSettings.get_settings()
|
||||
|
||||
context = {
|
||||
**self.admin_site.each_context(request),
|
||||
'title': 'Send Test Email',
|
||||
'settings': settings,
|
||||
'opts': self.model._meta,
|
||||
'default_from_email': settings.from_email,
|
||||
'default_to_email': request.user.email,
|
||||
}
|
||||
|
||||
return render(request, 'admin/system/emailsettings/test_email.html', context)
|
||||
|
||||
def send_test_email(self, request):
|
||||
"""Send test email to verify configuration"""
|
||||
if request.method != 'POST':
|
||||
return JsonResponse({'error': 'POST required'}, status=405)
|
||||
|
||||
from django.utils import timezone
|
||||
from igny8_core.business.billing.services.email_service import EmailService
|
||||
|
||||
to_email = request.POST.get('to_email', request.user.email)
|
||||
subject = request.POST.get('subject', 'IGNY8 Test Email')
|
||||
|
||||
# Create fresh EmailService instance to pick up latest settings
|
||||
service = EmailService()
|
||||
settings = EmailSettings.get_settings()
|
||||
|
||||
test_html = f"""
|
||||
<html>
|
||||
<body style="font-family: Arial, sans-serif; padding: 20px;">
|
||||
<h1 style="color: #6366f1;">IGNY8 Email Test</h1>
|
||||
<p>This is a test email to verify your email configuration.</p>
|
||||
|
||||
<h3>Configuration Details:</h3>
|
||||
<ul>
|
||||
<li><strong>Provider:</strong> {settings.email_provider.upper()}</li>
|
||||
<li><strong>From:</strong> {settings.from_name} <{settings.from_email}></li>
|
||||
<li><strong>Reply-To:</strong> {settings.reply_to_email}</li>
|
||||
<li><strong>Sent At:</strong> {timezone.now().strftime('%Y-%m-%d %H:%M:%S UTC')}</li>
|
||||
</ul>
|
||||
|
||||
<p style="color: #22c55e; font-weight: bold;">
|
||||
✓ If you received this email, your email configuration is working correctly!
|
||||
</p>
|
||||
|
||||
<hr style="margin: 20px 0; border: none; border-top: 1px solid #e5e7eb;">
|
||||
<p style="font-size: 12px; color: #6b7280;">
|
||||
This is an automated test email from IGNY8 Admin.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
try:
|
||||
result = service.send_transactional(
|
||||
to=to_email,
|
||||
subject=subject,
|
||||
html=test_html,
|
||||
tags=['test', 'admin-test'],
|
||||
)
|
||||
|
||||
if result.get('success'):
|
||||
# Log the test email
|
||||
EmailLog.objects.create(
|
||||
message_id=result.get('id', ''),
|
||||
to_email=to_email,
|
||||
from_email=settings.from_email,
|
||||
subject=subject,
|
||||
template_name='admin_test',
|
||||
status='sent',
|
||||
provider=result.get('provider', settings.email_provider),
|
||||
tags=['test', 'admin-test'],
|
||||
)
|
||||
|
||||
messages.success(
|
||||
request,
|
||||
f'Test email sent successfully to {to_email} via {result.get("provider", "unknown").upper()}!'
|
||||
)
|
||||
else:
|
||||
messages.error(request, f'Failed to send: {result.get("error", "Unknown error")}')
|
||||
|
||||
except Exception as e:
|
||||
messages.error(request, f'Error sending test email: {str(e)}')
|
||||
|
||||
return redirect(reverse('admin:system_emailsettings_changelist'))
|
||||
|
||||
def has_add_permission(self, request):
|
||||
"""Only allow one instance (singleton)"""
|
||||
return not EmailSettings.objects.exists()
|
||||
|
||||
@@ -16,6 +16,52 @@ class EmailSettings(models.Model):
|
||||
These settings work alongside IntegrationProvider (resend) configuration.
|
||||
"""
|
||||
|
||||
EMAIL_PROVIDER_CHOICES = [
|
||||
('resend', 'Resend'),
|
||||
('smtp', 'SMTP'),
|
||||
]
|
||||
|
||||
# Email provider selection
|
||||
email_provider = models.CharField(
|
||||
max_length=20,
|
||||
choices=EMAIL_PROVIDER_CHOICES,
|
||||
default='resend',
|
||||
help_text='Active email service provider'
|
||||
)
|
||||
|
||||
# SMTP Configuration
|
||||
smtp_host = models.CharField(
|
||||
max_length=255,
|
||||
blank=True,
|
||||
help_text='SMTP server hostname (e.g., smtp.gmail.com)'
|
||||
)
|
||||
smtp_port = models.IntegerField(
|
||||
default=587,
|
||||
help_text='SMTP server port (587 for TLS, 465 for SSL, 25 for plain)'
|
||||
)
|
||||
smtp_username = models.CharField(
|
||||
max_length=255,
|
||||
blank=True,
|
||||
help_text='SMTP authentication username'
|
||||
)
|
||||
smtp_password = models.CharField(
|
||||
max_length=255,
|
||||
blank=True,
|
||||
help_text='SMTP authentication password'
|
||||
)
|
||||
smtp_use_tls = models.BooleanField(
|
||||
default=True,
|
||||
help_text='Use TLS encryption (recommended for port 587)'
|
||||
)
|
||||
smtp_use_ssl = models.BooleanField(
|
||||
default=False,
|
||||
help_text='Use SSL encryption (for port 465)'
|
||||
)
|
||||
smtp_timeout = models.IntegerField(
|
||||
default=30,
|
||||
help_text='SMTP connection timeout in seconds'
|
||||
)
|
||||
|
||||
# Default sender settings
|
||||
from_email = models.EmailField(
|
||||
default='noreply@igny8.com',
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
# Generated by Django 5.2.10 on 2026-01-08 06:40
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('system', '0020_add_email_models'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='emailsettings',
|
||||
name='email_provider',
|
||||
field=models.CharField(choices=[('resend', 'Resend'), ('smtp', 'SMTP')], default='resend', help_text='Active email service provider', max_length=20),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='emailsettings',
|
||||
name='smtp_host',
|
||||
field=models.CharField(blank=True, help_text='SMTP server hostname (e.g., smtp.gmail.com)', max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='emailsettings',
|
||||
name='smtp_password',
|
||||
field=models.CharField(blank=True, help_text='SMTP authentication password', max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='emailsettings',
|
||||
name='smtp_port',
|
||||
field=models.IntegerField(default=587, help_text='SMTP server port (587 for TLS, 465 for SSL, 25 for plain)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='emailsettings',
|
||||
name='smtp_timeout',
|
||||
field=models.IntegerField(default=30, help_text='SMTP connection timeout in seconds'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='emailsettings',
|
||||
name='smtp_use_ssl',
|
||||
field=models.BooleanField(default=False, help_text='Use SSL encryption (for port 465)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='emailsettings',
|
||||
name='smtp_use_tls',
|
||||
field=models.BooleanField(default=True, help_text='Use TLS encryption (recommended for port 587)'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='emailsettings',
|
||||
name='smtp_username',
|
||||
field=models.CharField(blank=True, help_text='SMTP authentication username', max_length=255),
|
||||
),
|
||||
]
|
||||
Reference in New Issue
Block a user