title: "Email Setup" page: email-setup section: Advanced parent: Advanced parent_href: /docs/fetch

Email Setup

Configure transactional email for your app. wwwhat sends emails via a background job queue — form submissions return immediately while delivery happens asynchronously.

How It Works

When a form submission includes w-email-* hidden fields, wwwhat queues an email job immediately after saving the record. The user is redirected without waiting for the SMTP handshake or API call to complete. A slow or failed delivery doesn't block the form response.

SMTP Setup

Add an [email] section and [email.smtp] to wwwhat.toml. Use ${ENV_VAR} to keep credentials out of your config file.

wwwhat.toml
[email]
from = "hello@example.com"
from_name = "My App"

[email.smtp]
host = "smtp.gmail.com"
port = 587
username = "${SMTP_USER}"
password = "${SMTP_PASS}"
KeyDefaultDescription
fromSender email address (required)
from_nameDisplay name shown to recipients
template_diremailsDirectory containing HTML email templates
hostSMTP server hostname (required)
port587SMTP port (587 for STARTTLS, 465 for SSL)
usernameSMTP username (supports ${ENV_VAR})
passwordSMTP password (supports ${ENV_VAR})
Tip: Most SMTP providers (Gmail, Mailgun, Postmark, SendGrid) use port 587 with STARTTLS. wwwhat connects using STARTTLS by default. For port 465, SMTP over TLS is used automatically.

Common SMTP hosts:

ProviderHostPort
Gmailsmtp.gmail.com587
Mailgunsmtp.mailgun.org587
Postmarksmtp.postmarkapp.com587
SendGridsmtp.sendgrid.net587
Amazon SESemail-smtp.us-east-1.amazonaws.com587

Resend API

Use the Resend API instead of SMTP. Resend is simpler to set up and has a generous free tier (3,000 emails/month).

wwwhat.toml
[email]
from = "hello@example.com"
from_name = "My App"

[email.api]
provider = "resend"
api_key = "${RESEND_API_KEY}"

Configure either [email.smtp] or [email.api], not both. wwwhat uses whichever is present.

Tip: To use Resend, your sender email must be on a verified domain in the Resend dashboard. For testing, Resend provides a shared onboarding@resend.dev sender you can use before verifying your own domain.

Email Templates

Email templates are HTML files in the emails/ directory (configurable via template_dir). They use the same #variable# syntax as page templates, including all filters.

emails/welcome.html
<!DOCTYPE html>
<html>
<body style="font-family: sans-serif; max-width: 600px; margin: 0 auto; padding: 20px;">

  <h1 style="color: #111;">Welcome, #name|capitalize#!</h1>
  <p>Thanks for signing up at #site_name#. Your account is ready.</p>

  <p style="margin: 30px 0;">
    <a href="#dashboard_url#"
       style="background: #2563eb; color: white; padding: 12px 24px;
              text-decoration: none; border-radius: 6px; font-weight: bold;">
      Go to Dashboard
    </a>
  </p>

  <p style="color: #666; font-size: 0.875rem;">
    If you didn't create this account, you can safely ignore this email.
  </p>

</body>
</html>

Templates support all built-in filters:

Trigger Email from a Form

Add hidden fields with the w-email- prefix to any form. When the form is submitted, wwwhat saves the record and queues an email automatically.

site/contact.html
<form w-action="create" w-store="messages" w-redirect="/contact?sent=1" w-validate>
  <input type="hidden" name="w-email-to" value="admin@example.com">
  <input type="hidden" name="w-email-subject" value="New Contact Message">
  <input type="hidden" name="w-email-template" value="contact">

  <label>Name</label>
  <input type="text" name="name" w-required placeholder="Your name">

  <label>Email</label>
  <input type="email" name="email" w-required w-type="email" placeholder="you@example.com">

  <label>Message</label>
  <textarea name="message" w-required placeholder="How can we help?"></textarea>

  <button type="submit" class="btn btn-primary">Send Message</button>
</form>
Hidden FieldDescription
w-email-toRecipient address — required to trigger an email
w-email-subjectEmail subject line (default: "Notification")
w-email-templateTemplate filename from emails/, without .html

All form field values are passed as template variables. In this example, #name#, #email#, and #message# are available inside emails/contact.html.

emails/contact.html
<h2>New Contact Submission</h2>
<p><strong>From:</strong> #name# &lt;#email#&gt;</p>
<hr>
<p>#message#</p>

Environment Variables

Any value in wwwhat.toml can reference an environment variable using ${VAR_NAME} syntax. Variables are resolved at server startup from the process environment.

For local development, create a .env file in your project root. wwwhat loads it automatically if present:

.env
SMTP_USER=you@gmail.com
SMTP_PASS=your-app-password
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxx
Note: Never commit .env files to version control. Add .env to your .gitignore. In production, set environment variables through your hosting platform (Docker env flags, systemd environment files, Hetzner/DigitalOcean app settings).

If an environment variable is not set at runtime, wwwhat logs a warning and uses the raw string as-is (e.g., "${SMTP_PASS}"), which will cause the email to fail. Check your server logs if email is not working.