Configuring SMTP and Email Templates for Self-Hosted Supabase

Complete guide to setting up custom SMTP providers and email templates for self-hosted Supabase authentication workflows.

Cover Image for Configuring SMTP and Email Templates for Self-Hosted Supabase

If you've deployed self-hosted Supabase and tried to sign up a user, you've probably noticed something frustrating: emails don't work out of the box. Unlike Supabase Cloud, which provides a built-in SMTP server for development, self-hosted deployments require you to configure your own email provider. This guide walks through everything you need to set up reliable email delivery for authentication flows.

Why SMTP Configuration Matters

Email is the backbone of most authentication systems. Password resets, magic links, email verification, and team invitations all depend on reliable email delivery. Without proper SMTP configuration, your self-hosted Supabase instance is essentially broken for production use.

The good news: Supabase Auth works with any email service that supports SMTP. The challenge: the configuration isn't well-documented for self-hosted deployments, and there are several gotchas that can leave you debugging for hours.

Choosing an SMTP Provider

Before diving into configuration, you need an SMTP provider. Here are the most common options for self-hosted Supabase deployments:

Transactional Email Services (Recommended)

ProviderFree TierNotes
Resend3,000/monthDeveloper-friendly, excellent API
Postmark100/monthGreat deliverability, strict sender verification
SendGrid100/dayPopular choice, extensive documentation
Amazon SES62,000/month (with EC2)Cheapest at scale, more setup required
Mailgun1,000/monthReliable, good EU data residency options

Self-Hosted Options

If you want to avoid third-party services entirely, you can run your own mail server with tools like Mailcow, Mail-in-a-Box, or Postal. However, this adds significant operational complexity and deliverability challenges. Unless you have specific compliance requirements, a managed transactional email service is typically the better choice.

Basic SMTP Configuration

For self-hosted Supabase using Docker Compose, SMTP configuration happens through environment variables in your .env file and the Auth service configuration.

Step 1: Update Your .env File

Add the following variables to your .env file:

# SMTP Configuration
SMTP_HOST=smtp.resend.com
SMTP_PORT=465
SMTP_USER=resend
SMTP_PASS=re_your_api_key_here
[email protected]
SMTP_SENDER_NAME=YourAppName

# Email behavior
ENABLE_EMAIL_SIGNUP=true
ENABLE_EMAIL_AUTOCONFIRM=false

Step 2: Configure the Auth Container

In your docker-compose.yml, ensure the Auth service has access to these environment variables:

auth:
  image: supabase/gotrue:v2.158.1
  environment:
    GOTRUE_SMTP_HOST: ${SMTP_HOST}
    GOTRUE_SMTP_PORT: ${SMTP_PORT}
    GOTRUE_SMTP_USER: ${SMTP_USER}
    GOTRUE_SMTP_PASS: ${SMTP_PASS}
    GOTRUE_SMTP_ADMIN_EMAIL: ${SMTP_ADMIN_EMAIL}
    GOTRUE_SMTP_SENDER_NAME: ${SMTP_SENDER_NAME}
    GOTRUE_MAILER_AUTOCONFIRM: ${ENABLE_EMAIL_AUTOCONFIRM}

Step 3: Port Selection

SMTP typically uses one of three ports:

  • Port 465: SSL/TLS (recommended for most providers)
  • Port 587: STARTTLS (common alternative)
  • Port 25: Unencrypted (avoid for security reasons)

If you're experiencing timeout issues with port 465, try switching to 587. Some providers and network configurations handle STARTTLS better than implicit TLS.

Step 4: Restart and Test

After updating your configuration:

docker compose down
docker compose up -d

Test by signing up a new user through your application or the Supabase Studio interface.

Customizing Email Templates

Default Supabase email templates are functional but generic. For production, you'll want branded templates that match your application's look and feel.

Template Types

Supabase Auth uses these email templates:

TemplateTrigger
ConfirmationNew user signs up with email
InviteAdmin invites user to the platform
RecoveryUser requests password reset
Magic LinkUser signs in with magic link
Email ChangeUser changes their email address

Template Variables

All templates support Go Template syntax with these variables:

{{ .ConfirmationURL }} - The full URL for the action
{{ .Token }}           - The raw token
{{ .TokenHash }}       - Hashed version of the token
{{ .SiteURL }}         - Your configured site URL
{{ .Email }}           - User's email address
{{ .NewEmail }}        - New email (for email change)
{{ .OldEmail }}        - Old email (for email change)
{{ .Data }}            - User metadata object

Setting Up Custom Templates

For self-hosted deployments, templates must be hosted at accessible URLs. The Auth service fetches templates from these URLs at runtime.

Option 1: Host Templates on Your Server

Create a simple template server or use your existing web server:

# nginx configuration
location /email-templates/ {
    alias /var/www/email-templates/;
    default_type text/html;
}

Then configure the Auth service:

auth:
  environment:
    GOTRUE_MAILER_TEMPLATES_CONFIRMATION: https://yourdomain.com/email-templates/confirmation.html
    GOTRUE_MAILER_TEMPLATES_INVITE: https://yourdomain.com/email-templates/invite.html
    GOTRUE_MAILER_TEMPLATES_RECOVERY: https://yourdomain.com/email-templates/recovery.html
    GOTRUE_MAILER_TEMPLATES_MAGIC_LINK: https://yourdomain.com/email-templates/magic-link.html
    GOTRUE_MAILER_TEMPLATES_EMAIL_CHANGE: https://yourdomain.com/email-templates/email-change.html

Option 2: Use Supabase Storage

If you're running Supabase Storage, you can host templates in a public bucket. Just ensure the bucket is accessible from within your Docker network.

Example Template

Here's a production-ready confirmation email template:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Confirm Your Email</title>
</head>
<body style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
  <div style="text-align: center; margin-bottom: 30px;">
    <img src="https://yourdomain.com/logo.png" alt="Your App" style="height: 40px;">
  </div>
  
  <h1 style="font-size: 24px; font-weight: 600; margin-bottom: 20px;">
    Confirm your email address
  </h1>
  
  <p>Thanks for signing up! Please confirm your email address by clicking the button below.</p>
  
  <div style="text-align: center; margin: 30px 0;">
    <a href="{{ .ConfirmationURL }}" 
       style="background-color: #10b981; color: white; padding: 12px 30px; text-decoration: none; border-radius: 6px; font-weight: 500; display: inline-block;">
      Confirm Email
    </a>
  </div>
  
  <p style="color: #666; font-size: 14px;">
    If the button doesn't work, copy and paste this link into your browser:
    <br>
    <a href="{{ .ConfirmationURL }}" style="color: #10b981;">{{ .ConfirmationURL }}</a>
  </p>
  
  <hr style="border: none; border-top: 1px solid #eee; margin: 30px 0;">
  
  <p style="color: #999; font-size: 12px; text-align: center;">
    You received this email because someone signed up with {{ .Email }}.
    If this wasn't you, you can safely ignore this email.
  </p>
</body>
</html>

Email Deliverability Best Practices

Setting up SMTP is only half the battle. Poor deliverability means your emails land in spam folders—or don't arrive at all.

Configure DNS Records

Work with your SMTP provider to set up these DNS records:

SPF Record: Authorizes your SMTP provider to send on your behalf.

v=spf1 include:_spf.resend.com ~all

DKIM Record: Cryptographically signs emails to prevent spoofing.

DMARC Record: Tells receiving servers how to handle failed SPF/DKIM checks.

v=DMARC1; p=quarantine; rua=mailto:[email protected]

Use a Subdomain for Transactional Email

Send auth emails from a subdomain like [email protected] rather than your primary domain. This isolates your transactional email reputation from any marketing emails you might send.

Monitor Bounce Rates

Most SMTP providers offer bounce and complaint monitoring. Keep an eye on these metrics—high bounce rates can damage your sender reputation and lead to deliverability issues.

Using the Send Email Hook

For more control over email sending, Supabase offers a Send Email Hook. This is useful when you want to:

  • Use a provider that doesn't support SMTP (API-only services)
  • Implement complex templating with tools like React Email
  • Add custom logic before sending (rate limiting, A/B testing)

The hook is configured as a Postgres function that Supabase Auth calls instead of using SMTP directly. Check the auth providers documentation for implementation details.

Troubleshooting Common Issues

Emails not sending at all

  1. Check Auth container logs: docker logs supabase-auth
  2. Verify SMTP credentials are correct
  3. Ensure the SMTP port isn't blocked by your firewall
  4. Test your SMTP credentials with a tool like swaks

Emails going to spam

  1. Verify SPF, DKIM, and DMARC records are configured
  2. Check your sender reputation with tools like Mail Tester
  3. Ensure your From address domain matches your DKIM domain

Connection timeouts

  1. Try switching between ports 465 and 587
  2. Check if your VPS provider blocks outbound SMTP (common with some providers)
  3. Verify the SMTP host is resolvable from within your Docker network

Template changes not applying

  1. Templates are fetched at runtime—ensure the URL is accessible
  2. Check for caching at the reverse proxy level
  3. Verify the template URL is reachable from the Auth container

How Supascale Simplifies This

If manual SMTP configuration feels like unnecessary complexity, you're not alone. Supascale provides a management layer for self-hosted Supabase that includes:

While SMTP configuration still requires your own provider, Supascale reduces the operational burden of managing self-hosted Supabase—letting you focus on building your application rather than wrestling with infrastructure.

Conclusion

Configuring SMTP for self-hosted Supabase isn't difficult once you understand the moving parts. The key steps are:

  1. Choose a reliable SMTP provider
  2. Configure environment variables in your Docker Compose setup
  3. Set up DNS records for deliverability
  4. Customize email templates to match your brand

The extra effort pays off with full control over your authentication emails—no rate limits, no third-party branding, and complete data sovereignty.

For teams looking to reduce the operational complexity of self-hosted Supabase, check out Supascale's pricing—a one-time purchase that includes unlimited projects and ongoing updates.


Further Reading