Email Setup
Configure email providers - Resend, SMTP, or Console for development
TL;DR: Emails log to console by default. Set
EMAIL_PROVIDER=resendfor production.
Straktur supports multiple email providers through a unified adapter system.
Supported Providers
Console
Default for development - emails are logged to your terminal instead of being sent.
EMAIL_PROVIDER=console
EMAIL_FROM=noreply@localhostNo configuration needed. Just check your terminal for email output.
For security, HTML content is not logged (may contain tokens). Only subject, recipient, and text preview are shown.
Resend
Recommended for production - modern API, great developer experience.
Setup
- Create account at resend.com
- Verify your domain in Domains section
- Create API key in API Keys
EMAIL_PROVIDER=resend
RESEND_API_KEY=re_123456789
EMAIL_FROM=hello@yourdomain.comYou must verify your domain to send from custom addresses. Unverified accounts can only send to your own email.
SMTP
Universal option - works with any email service that supports SMTP.
Setup
EMAIL_PROVIDER=smtp
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=your-username
SMTP_PASS=your-password
SMTP_SECURE=false
EMAIL_FROM=hello@yourdomain.comCommon SMTP Configurations
SMTP does not work on Edge Runtime (Vercel Edge Functions). Use Resend for edge deployments.
Docker Development
Docker Compose includes Mailpit - a local SMTP server with web UI.
EMAIL_PROVIDER=smtp
SMTP_HOST=mailpit
SMTP_PORT=1025
EMAIL_FROM=noreply@localhostView emails at http://localhost:8080
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
EMAIL_PROVIDER | No | console | console, resend, or smtp |
EMAIL_FROM | Yes | - | Sender address |
EMAIL_REPLY_TO | No | - | Reply-to address |
RESEND_API_KEY | If Resend | - | Resend API key |
SMTP_HOST | If SMTP | - | SMTP server hostname |
SMTP_PORT | If SMTP | 587 | SMTP port |
SMTP_USER | If SMTP | - | SMTP username |
SMTP_PASS | If SMTP | - | SMTP password |
SMTP_SECURE | If SMTP | false | Use SSL/TLS |
Sending Emails
Basic Email
import { sendEmail } from "@/lib/email"
await sendEmail({
to: "user@example.com",
subject: "Hello",
html: "<h1>Welcome!</h1>",
text: "Welcome!", // plaintext fallback
})With React Email Template
import { sendTemplatedEmail } from "@/lib/email"
import { WelcomeEmail } from "@/emails/welcome-email"
await sendTemplatedEmail(
WelcomeEmail,
{ userName: "John", loginUrl: "https://..." },
{ to: "user@example.com", subject: "Welcome to Straktur" }
)With Attachments
Pass an attachments array on any send call. Works with both Resend and SMTP providers — each attachment is a Buffer plus a filename and optional MIME type.
import { sendEmail } from "@/lib/email"
import { getStorage } from "@/lib/storage"
// Pull a file out of storage (see Storage docs)
const pdfBuffer = await getStorage().getObject("orgs/abc/invoices/INV-2026-001.pdf")
await sendEmail({
to: "client@example.com",
subject: "Your invoice",
html: "<p>Invoice attached.</p>",
attachments: [
{
filename: "INV-2026-001.pdf",
content: pdfBuffer,
contentType: "application/pdf",
},
],
})The EmailAttachment shape:
| Field | Type | Required | Description |
|---|---|---|---|
filename | string | Yes | Name the recipient sees |
content | Buffer | Yes | File bytes |
contentType | string | No | MIME type, e.g. "application/pdf". Most clients infer from filename if omitted, but set it to be safe. |
Attachments are sent inline in the SMTP/Resend payload, which counts against your provider's message size limit (Resend: 40 MB, most SMTP servers: 10–25 MB). For large files, send a link to a presigned download URL instead of attaching.