{% extends "base.html" %} {% block title %}Mailer{% endblock %} {% block breadcrumb %}Mailer{% endblock %} {% block content %} {# ═══════════════════════════════════════════════════════════════════ AQUILIA ADMIN — COMPREHENSIVE MAILER DASHBOARD Providers · Configuration · Security · Templates · Send Test · Health ═══════════════════════════════════════════════════════════════════ #}

Mailer {% if available and enabled %} {{ 'Healthy' if is_healthy else 'Active' }} {% elif available %} Disabled {% else %} Not Configured {% endif %}

AquilaMail — Production-ready async mail subsystem • Providers, templates, security & delivery

{% if not available %} {# ═══ NOT CONFIGURED STATE ═══ #}

Mail Subsystem Not Configured

Enable the mail integration in your workspace.py to use the Mailer admin page.

workspace.py
app.integrate(Integration.mail(
    default_from="noreply@myapp.com",
    console_backend=True,
    providers=[
        Integration.MailProvider.SMTP(
            name="smtp",
            host="smtp.example.com",
            port=587,
        ),
    ],
))
{% else %} {# ═══ STAT CARDS ═══ #}
{{ provider_count }}
Providers
{{ active_provider_count }} active
{{ stats.get('total_sent', 0) if stats is mapping else 0 }}
Sent
Total delivered
{{ stats.get('total_failed', 0) if stats is mapping else 0 }}
Failed
Delivery failures
{{ stats.get('total_queued', 0) if stats is mapping else 0 }}
Queued
Pending delivery
{{ rate_limit.get('global_per_minute', 1000) if rate_limit is mapping else 1000 }}
Rate Limit
msg/min (global)
{{ retry.get('max_attempts', 5) if retry is mapping else 5 }}
Max Retries
Per envelope
{# ═══ TABS ═══ #}
{# ════════════════════════════════════════════════════════════════════ TAB: OVERVIEW ════════════════════════════════════════════════════════════════════ #}
{# General Settings #}

General Settings

Enabled {{ 'Yes' if enabled else 'No' }}
Default From {{ default_from }}
Reply-To {{ default_reply_to or '—' }}
Subject Prefix {{ subject_prefix or '(none)' }}
Preview Mode {{ 'Yes' if preview_mode else 'No' }}
Console Backend {{ 'Yes' if console_backend else 'No' }}
{# Delivery Pipeline #}

Delivery Pipeline

Active Providers {{ active_provider_count }} / {{ provider_count }}
Health Status {{ 'Healthy' if is_healthy else 'Unhealthy' }}
Retry Attempts {{ retry.get('max_attempts', 5) if retry is mapping else 5 }}
Base Delay {{ retry.get('base_delay', 1.0) if retry is mapping else 1.0 }}s
Jitter {{ 'Enabled' if (retry.get('jitter', true) if retry is mapping else true) else 'Disabled' }}
Metrics {{ 'Enabled' if metrics_enabled else 'Disabled' }}
{# Rate Limiting #}

Rate Limiting

Global Limit {{ rate_limit.get('global_per_minute', 1000) if rate_limit is mapping else 1000 }} msg/min
Per Domain {{ rate_limit.get('per_domain_per_minute', 100) if rate_limit is mapping else 100 }} msg/min
Per Provider {{ rate_limit.get('per_provider_per_minute', '—') if rate_limit is mapping else '—' }}
{# Queue Settings #}

Queue & Storage

Batch Size {{ queue.get('batch_size', 50) if queue is mapping else 50 }}
Poll Interval {{ queue.get('poll_interval', 1.0) if queue is mapping else 1.0 }}s
Dedup Window {{ queue.get('dedupe_window_seconds', 3600) if queue is mapping else 3600 }}s
Retention {{ queue.get('retention_days', 30) if queue is mapping else 30 }} days
{# ════════════════════════════════════════════════════════════════════ TAB: PROVIDERS ════════════════════════════════════════════════════════════════════ #}
{% if providers|length > 0 %}
{% for p in providers %}
{% if p.type == 'smtp' %} {% elif p.type == 'ses' %} {% elif p.type == 'sendgrid' %} {% elif p.type == 'console' %} {% elif p.type == 'file' %} {% else %}{% endif %}
{{ p.name }}
{{ p.type_display }}
{% if p.status == 'active' %}Active {% elif p.status == 'disabled' %}Disabled {% else %}Inactive{% endif %}
Priority
{{ p.priority }}
Rate Limit
{{ p.rate_limit_per_min }} msg/min
{% if p.type == 'smtp' %}
Host
{{ p.host or 'localhost' }}
Port
{{ p.port or 587 }}
TLS
{{ 'STARTTLS' if p.use_tls else ('SSL' if p.use_ssl else 'None') }}
Timeout
{{ p.timeout }}s
{% endif %}
{% endfor %}
{% else %}

No Providers Configured

Add providers in your Integration.mail(providers=[...]) configuration.

{% endif %} {# Provider Types Reference #}
Available Provider Types

SMTP

Production-grade async SMTP via aiosmtplib. Supports STARTTLS, direct SSL, connection pooling, batch send, and TLS certificate validation.

AWS SES

Amazon Simple Email Service via aiobotocore. Auto-region selection, IAM auth, configuration sets, and event notifications.

SendGrid

SendGrid API v3 via httpx. API key auth, dynamic templates, categories, and click/open tracking.

Console

Development provider — prints emails to stdout/logger. Does not actually deliver messages. Always healthy.

File

Development provider — writes emails to files on disk. Useful for visual inspection and automated testing.
{# ════════════════════════════════════════════════════════════════════ TAB: CONFIGURATION ════════════════════════════════════════════════════════════════════ #}
Full Configuration (Read-Only)
{{ config|tojson(indent=2) if config else '{}' }}
Workspace Integration Code
# workspace.py
from aquilia import Integration

workspace = (
    Workspace("MyApp")
    .integrate(Integration.mail(
        default_from="{{ default_from }}",{% if subject_prefix %}
        subject_prefix="{{ subject_prefix }}",{% endif %}{% if console_backend %}
        console_backend=True,{% endif %}{% if preview_mode %}
        preview_mode=True,{% endif %}
        providers=[
            {% for p in providers %}{"name": "{{ p.name }}", "type": "{{ p.type }}"{% if p.type == 'smtp' %}, "host": "{{ p.host or 'smtp.example.com' }}", "port": {{ p.port or 587 }}{% endif %}},
            {% endfor %}
        ],
    ))
    .integrate(Integration.admin(
        modules=Integration.AdminModules()
            .enable_mailer()
    ))
)
Quick Reference — API Usage

Sync Send

from aquilia.mail import send_mail

send_mail(
    subject="Hello",
    body="World",
    to=["user@example.com"],
)

Async Send

from aquilia.mail import asend_mail

await asend_mail(
    subject="Hello",
    body="World",
    to=["user@example.com"],
)

Template Message

from aquilia.mail import TemplateMessage

msg = TemplateMessage(
    template="welcome.aqt",
    context={"user": {"name": "Asha"}},
    to=["asha@example.com"],
)
await msg.asend()

Attachments

from aquilia.mail import EmailMessage

msg = EmailMessage(
    subject="Report",
    body="Attached",
    to=["admin@example.com"],
)
msg.attach("report.pdf", data, "application/pdf")
msg.attach_file("/tmp/invoice.pdf")
await msg.asend()

Multi-Alternatives

from aquilia.mail import EmailMultiAlternatives

msg = EmailMultiAlternatives(
    subject="Newsletter",
    body="Plain text fallback",
    to=["sub@example.com"],
)
msg.attach_alternative(html, "text/html")
await msg.asend()

Priority & Idempotency

from aquilia.mail import EmailMessage
from aquilia.mail import Priority

msg = EmailMessage(
    subject="Critical Alert",
    body="Server down!",
    to=["ops@example.com"],
    priority=Priority.CRITICAL.value,
    idempotency_key="alert-server-1",
)
await msg.asend()
{# ════════════════════════════════════════════════════════════════════ TAB: SECURITY ════════════════════════════════════════════════════════════════════ #}

DKIM Signing

DKIM Enabled {{ 'Yes' if (security.get('dkim_enabled') if security is mapping else false) else 'No' }}
DKIM Domain {{ (security.get('dkim_domain') if security is mapping else none) or '—' }}
DKIM Selector {{ (security.get('dkim_selector') if security is mapping else 'aquilia') or 'aquilia' }}

Transport Security

Require TLS {{ 'Yes' if (security.get('require_tls', true) if security is mapping else true) else 'No' }}
PII Redaction {{ 'Enabled' if (security.get('pii_redaction_enabled') if security is mapping else false) else 'Disabled' }}

Allowed From Domains

{% set domains = security.get('allowed_from_domains', []) if security is mapping else [] %} {% if domains|length > 0 %}
{% for d in domains %} {{ d }} {% endfor %}
{% else %}
No domain restrictions — any sender domain is allowed.
{% endif %}

Observability

Metrics {{ 'Enabled' if metrics_enabled else 'Disabled' }}
Tracing {{ 'Enabled' if tracing_enabled else 'Disabled' }}
{# Security Best Practices #}
Security Best Practices
{% set checks = [ ('DKIM signing', security.get('dkim_enabled') if security is mapping else false, 'Enable DKIM to authenticate your emails and improve deliverability'), ('TLS required', security.get('require_tls', true) if security is mapping else true, 'Require TLS for all SMTP connections to prevent eavesdropping'), ('PII redaction', security.get('pii_redaction_enabled') if security is mapping else false, 'Redact email addresses and personal data from logs'), ('Domain whitelist', (security.get('allowed_from_domains', []) if security is mapping else [])|length > 0, 'Restrict which domains can be used as sender addresses'), ('Preview mode off', not preview_mode, 'Preview mode should be disabled in production'), ] %} {% for label, ok, hint in checks %}
{% if ok %} {% else %} {% endif %}
{{ label }}
{{ hint }}
{% endfor %}
{# ════════════════════════════════════════════════════════════════════ TAB: TEMPLATES ════════════════════════════════════════════════════════════════════ #}

ATS Template Engine

Auto-Escape {{ 'Enabled' if (templates.get('auto_escape', true) if templates is mapping else true) else 'Disabled' }}
Cache Compiled {{ 'Enabled' if (templates.get('cache_compiled', true) if templates is mapping else true) else 'Disabled' }}
Strict Mode {{ 'Enabled' if (templates.get('strict_mode') if templates is mapping else false) else 'Disabled' }}

Template Directories

{% set dirs = templates.get('template_dirs', ['mail_templates']) if templates is mapping else ['mail_templates'] %} {% for d in dirs %}
{{ d }}
{% endfor %}
{# ATS Syntax Reference #}
ATS (Aquilia Template Syntax) Reference

Expressions

<< user.name >>
<< order.total >>
<< company.logo_url >>

Filters

<< name | title >>
<< price | currency("USD") >>
<< bio | truncate(120) >>

Control Flow

[[% if user.is_premium %]]
  Premium content here
[[% endif %]]

[[% for item in order.items %]]
  << item.name >>: << item.price >>
[[% endfor %]]

Template Inheritance

[[% extends "base_email.aqt" %]]

[[% block content %]]
  Your email body here
[[% endblock %]]
{# ════════════════════════════════════════════════════════════════════ TAB: SEND TEST EMAIL ════════════════════════════════════════════════════════════════════ #}

Send Test Email

{{ 'Preview Mode' if preview_mode else 'Live Send' }}
The email address to send the test email to
Leave empty to use default: {{ default_from }}
Leave empty to use the built-in Aquilia test email template with HTML
Provide custom HTML or leave empty for the built-in Aquilia-branded template
{# Recent send test results #}
Recent Test Sends
Time To Subject Status Envelope ID
No test emails sent in this session
{# ════════════════════════════════════════════════════════════════════ TAB: HEALTH CHECK ════════════════════════════════════════════════════════════════════ #}

Provider Health Check

Click "Run Health Check" to test connectivity to all configured providers

{# Troubleshooting Guide #}
Troubleshooting Guide

Connection Refused

Check that your SMTP host and port are correct. Ensure firewalls allow outbound connections. Common ports: 25 (SMTP), 465 (SSL), 587 (STARTTLS).

Authentication Failed

Verify username and password. For Gmail/Google Workspace, use App Passwords (not regular passwords). For SES, check IAM credentials.

Timeout Errors

Increase the timeout setting. Default is 30s. Check network latency to your SMTP server. Consider using a closer region for SES/SendGrid.

Rate Limiting

If you receive 429 or "rate limited" errors, reduce rate_limit_per_min per provider or increase the global limit. SES new accounts have strict sending limits.
{% endif %} {# ═══ Toast Notification ═══ #}
{% endblock %} {% block extra_js %} (function(){ const PREFIX = '{{ url_prefix|default("/admin") }}'; function _csrfHdrs(){var h={'Content-Type':'application/json'};var el=document.querySelector('meta[name="csrf-token"]');if(el&&el.content)h['X-CSRF-Token']=el.content;return h;} // ── Tab switching ── window.switchTab = function(name) { document.querySelectorAll('.ml-tab-panel').forEach(p => p.classList.remove('active')); document.querySelectorAll('.ml-tab').forEach(t => t.classList.remove('active')); const panel = document.getElementById('tab-' + name); if (panel) panel.classList.add('active'); // Find matching tab button document.querySelectorAll('.ml-tab').forEach(t => { if (t.textContent.trim().toLowerCase().replace(/\s+/g, '-') === name || t.onclick.toString().includes("'" + name + "'")) { t.classList.add('active'); } }); }; // ── Toast notification ── function showToast(msg, sub, type) { const toast = document.getElementById('mailerToast'); if (!toast) return; toast.className = 'ml-toast ' + type; toast.querySelector('.ml-toast-msg').textContent = msg; toast.querySelector('.ml-toast-sub').textContent = sub || ''; toast.classList.add('show'); setTimeout(() => toast.classList.remove('show'), 5000); } // ── Send Test Email ── const testHistory = []; window.sendTestEmail = function() { const btn = document.getElementById('sendTestBtn'); const status = document.getElementById('sendTestStatus'); const toVal = document.getElementById('testTo').value.trim(); if (!toVal) { showToast('Recipient email is required', '', 'err'); return; } btn.disabled = true; btn.innerHTML = ' Sending...'; status.textContent = 'Sending...'; const payload = { to: toVal, from_email: document.getElementById('testFrom').value.trim() || '', subject: document.getElementById('testSubject').value.trim() || 'Aquilia Test Email', body: document.getElementById('testBody').value.trim() || '', body_html: document.getElementById('testHtml').value.trim() || '', reply_to: document.getElementById('testReplyTo').value.trim() || '', priority: document.getElementById('testPriority').value, }; fetch(PREFIX + '/mailer/send-test/', { method: 'POST', headers: _csrfHdrs(), body: JSON.stringify(payload), }) .then(r => r.json()) .then(data => { btn.disabled = false; btn.innerHTML = ' Send Test Email'; if (data.success) { showToast('Test email sent successfully!', 'Envelope: ' + (data.envelope_id || 'N/A'), 'ok'); status.textContent = '✓ Sent'; status.style.color = '#22c55e'; addTestHistory(toVal, payload.subject, true, data.envelope_id, null); } else { showToast('Failed to send test email', data.error || 'Unknown error', 'err'); status.textContent = '✗ Failed'; status.style.color = '#ef4444'; addTestHistory(toVal, payload.subject, false, null, data.error); } }) .catch(err => { btn.disabled = false; btn.innerHTML = ' Send Test Email'; showToast('Network error', err.message, 'err'); status.textContent = '✗ Error'; status.style.color = '#ef4444'; addTestHistory(toVal, payload.subject, false, null, err.message); }); }; function addTestHistory(to, subject, success, envelopeId, error) { const now = new Date().toLocaleTimeString(); testHistory.unshift({ time: now, to: to, subject: subject, success: success, envelopeId: envelopeId, error: error }); renderTestHistory(); } function renderTestHistory() { const tbody = document.getElementById('testHistoryBody'); if (!tbody || testHistory.length === 0) return; let html = ''; testHistory.forEach(function(entry) { html += ''; html += '' + entry.time + ''; html += '' + entry.to + ''; html += '' + entry.subject + ''; html += ''; if (entry.success) { html += 'Sent'; } else { html += 'Failed'; } html += ''; html += '' + (entry.envelopeId || (entry.error ? entry.error.substring(0, 50) : '—')) + ''; html += ''; }); tbody.innerHTML = html; } window.resetTestForm = function() { document.getElementById('testTo').value = ''; document.getElementById('testFrom').value = ''; document.getElementById('testSubject').value = 'Aquilia Test Email'; document.getElementById('testBody').value = ''; document.getElementById('testHtml').value = ''; document.getElementById('testReplyTo').value = ''; document.getElementById('testPriority').value = 'normal'; document.getElementById('sendTestStatus').textContent = ''; }; // ── Health Check ── window.runHealthCheck = function() { const btn = document.getElementById('healthCheckBtn'); const container = document.getElementById('healthCheckResults'); btn.disabled = true; btn.innerHTML = ' Checking...'; fetch(PREFIX + '/mailer/health-check/', { method: 'POST', headers: _csrfHdrs(), }) .then(r => r.json()) .then(data => { btn.disabled = false; btn.innerHTML = ' Run Health Check'; let html = '
'; // Overall status html += '
'; html += ''; html += '' + (data.overall_healthy ? 'All Providers Healthy' : 'Some Providers Unhealthy') + ''; html += '' + data.checked_count + ' provider(s) checked'; html += '
'; // Per-provider results const providers = data.providers || {}; Object.keys(providers).forEach(function(name) { const r = providers[name]; html += '
'; html += ''; html += '' + name + ''; html += '' + (r.healthy ? 'Healthy' : 'Unhealthy') + ''; if (r.error) { html += '' + r.error + ''; } html += '
'; }); if (Object.keys(providers).length === 0) { html += '
No active providers to check
'; } html += '
'; container.innerHTML = html; showToast( data.overall_healthy ? 'All providers healthy' : 'Some providers unhealthy', data.checked_count + ' provider(s) checked', data.overall_healthy ? 'ok' : 'err' ); }) .catch(err => { btn.disabled = false; btn.innerHTML = ' Run Health Check'; container.innerHTML = '
Health check failed: ' + err.message + '
'; showToast('Health check failed', err.message, 'err'); }); }; // ── Spin animation ── if (!document.getElementById('mlSpinStyle')) { const style = document.createElement('style'); style.id = 'mlSpinStyle'; style.textContent = '@keyframes spin{from{transform:rotate(0)}to{transform:rotate(360deg)}}'; document.head.appendChild(style); } })(); {% endblock %}