Email Setup
This guide shows how to configure email sending for PWASK. We use different services for development (testing) and production (real emails).
Quick Setup
Development: Ethereal Email (Recommended)
Ethereal.email is a fake SMTP service perfect for testing emails without sending real ones.
Benefits:
- 100% free
- No signup required
- Instant test accounts
- Web interface to view sent emails
- No emails actually sent (perfect for testing)
Setup Steps:
-
Generate test account (automated):
# Run this Node.js script once to get credentials node -e "require('nodemailer').createTestAccount().then(account => console.log('EMAIL_HOST=smtp.ethereal.email\nEMAIL_PORT=587\nEMAIL_USER=' + account.user + '\nEMAIL_PASS=' + account.pass))" -
Add to
.env.local:EMAIL_HOST=smtp.ethereal.email EMAIL_PORT=587 EMAIL_USER=your_generated_user@ethereal.email EMAIL_PASS=your_generated_password EMAIL_NAME=PWASK Dev EMAIL_FROM=noreply@pwask.dev EMAIL_TO=test@ethereal.email -
View sent emails:
- Go to https://ethereal.email/messages
- Login with the credentials from step 1
- All "sent" emails appear here instantly
Alternative: Manual account creation
- Visit https://ethereal.email/create
- Click "Create Ethereal Account"
- Copy the credentials to your
.env.local
Production: Resend (Recommended)
Resend is a modern email API with excellent deliverability and developer experience.
Why Resend:
- ✅ 100 emails/day free forever
- ✅ 99% deliverability rate
- ✅ Simple API and SMTP
- ✅ Custom domain support
- ✅ Email analytics
- ✅ Great documentation
- ✅ No credit card required for free tier
Setup Steps:
-
Create account:
- Visit https://resend.com/signup
- Sign up with GitHub or email
-
Verify domain (recommended for production):
- Go to Domains
- Add your domain
- Add DNS records (SPF, DKIM, DMARC)
- Wait for verification (~5 minutes)
-
Generate API Key:
- Go to API Keys
- Create new API key
- Copy the key (starts with
re_)
-
Configure for SMTP (easier) or API:
Option A: SMTP (Recommended - no code changes needed)
EMAIL_HOST=smtp.resend.com EMAIL_PORT=587 EMAIL_USER=resend EMAIL_PASS=re_your_api_key_here EMAIL_NAME=PWASK EMAIL_FROM=noreply@yourdomain.com # Must use verified domain EMAIL_TO=support@yourdomain.comOption B: Resend API (requires code changes)
RESEND_API_KEY=re_your_api_key_here EMAIL_FROM=noreply@yourdomain.com -
Update email route (only if using API):
// src/app/api/sendmail/route.ts import { Resend } from 'resend'; const resend = new Resend(process.env.RESEND_API_KEY);
Alternative Production Services
1. SendGrid (Twilio)
- Free tier: 100 emails/day forever
- Pros: Industry standard, reliable
- Cons: More complex setup, owned by Twilio
- Website: sendgrid.com
Setup:
EMAIL_HOST=smtp.sendgrid.net
EMAIL_PORT=587
EMAIL_USER=apikey
EMAIL_PASS=SG.your_api_key_here
2. Mailgun
- Free tier: 5,000 emails/month (first 3 months), then 100 emails/day
- Pros: Powerful API, good deliverability
- Cons: Complex pricing after trial
- Website: mailgun.com
Setup:
EMAIL_HOST=smtp.mailgun.org
EMAIL_PORT=587
EMAIL_USER=postmaster@your-domain.mailgun.org
EMAIL_PASS=your_smtp_password
3. Amazon SES
- Free tier: 62,000 emails/month (if sending from EC2)
- Pros: Cheapest for high volume, reliable
- Cons: Complex setup, requires AWS account
- Website: aws.amazon.com/ses
4. Brevo (formerly Sendinblue)
- Free tier: 300 emails/day
- Pros: Higher free tier, includes SMS
- Cons: Includes branding in free tier
- Website: brevo.com
Setup:
EMAIL_HOST=smtp-relay.brevo.com
EMAIL_PORT=587
EMAIL_USER=your_brevo_email
EMAIL_PASS=your_brevo_smtp_key
Environment Variables Reference
# Required for all providers
EMAIL_HOST=smtp.provider.com # SMTP server hostname
EMAIL_PORT=587 # SMTP port (usually 587 for TLS)
EMAIL_USER=your_username # SMTP username
EMAIL_PASS=your_password # SMTP password or API key
EMAIL_NAME=Your App Name # Sender display name
EMAIL_FROM=noreply@yourdomain.com # From email address
EMAIL_TO=admin@yourdomain.com # Default recipient for admin emails
Testing Email Sending
1. Test with Stripe Webhook
After configuring email, test with a Stripe payment:
# Start Stripe CLI listener
stripe listen --forward-to localhost:3000/api/checkout/stripe/webhook
# Trigger a test payment
stripe trigger checkout.session.completed
Check your email service (Ethereal or Resend) to verify the email was sent.
2. Test with API Route Directly
Create a test script:
// scripts/test-email.ts
const response = await fetch('http://localhost:3000/api/sendmail', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
template: 'payment_confirmation',
to: 'test@example.com',
email: 'test@example.com',
name: 'Test User',
amount: '299 EUR',
plan: 'lifetime',
locale: 'en',
}),
});
console.log('Email sent:', await response.text());
Run with: tsx scripts/test-email.ts
Email Templates
PWASK includes React Email templates in src/emails/:
src/emails/
├── en/
│ ├── payment_confirmation.tsx
│ └── purchase_with_download.tsx
└── fr/
├── payment_confirmation.tsx
└── purchase_with_download.tsx
Available Templates
-
payment_confirmation.tsx
- Sent after successful payment
- Includes payment details and next steps
-
purchase_with_download.tsx
- Sent when payment includes a download
- Includes download link with expiry
Deliverability Best Practices
1. Domain Authentication
Always verify your domain with SPF, DKIM, and DMARC records:
SPF Record (example for Resend):
v=spf1 include:_spf.resend.com ~all
DKIM: Provided by your email service (add to DNS)
DMARC:
v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.com
2. From Address
- Use a verified domain (not @gmail.com in production)
- Use consistent "from" addresses
- Example:
noreply@yourdomain.com
3. Email Content
- Include plain text version
- Avoid spam trigger words
- Include unsubscribe link (for marketing emails)
- Keep HTML clean and responsive
4. Monitor Bounce Rates
- Check your email service dashboard regularly
- Remove bounced email addresses
- Monitor spam complaints
Troubleshooting
"Authentication failed"
- Verify
EMAIL_USERandEMAIL_PASSare correct - Check if using API key as password (common with Resend, SendGrid)
- Ensure no extra spaces in environment variables
"Connection timeout"
- Check
EMAIL_HOSTandEMAIL_PORT - Verify firewall allows outbound SMTP (port 587)
- Try port 465 (SSL) instead of 587 (TLS)
"Emails not received"
- Check spam/junk folders
- Verify domain is authenticated (SPF/DKIM)
- For Ethereal: check web interface at ethereal.email/messages
- For production: check email service logs/dashboard
"Invalid sender domain"
- Verify domain in email service dashboard
- Wait for DNS propagation (~24 hours)
- Use verified domain in
EMAIL_FROM
Security Notes
- Never commit
.env.localwith real credentials - Use environment variables in production (Vercel, etc.)
- Rotate keys if accidentally exposed
- Keep
EMAIL_PASSand API keys server-side only - Use separate accounts for dev/staging/production
Recommended: Dev → Production Flow
- Local Dev: Use Ethereal (no real emails sent)
- Staging: Use Resend sandbox mode or test domain
- Production: Use Resend with verified custom domain
This ensures you never accidentally send test emails to real users!
Related Documentation
- Getting Started — Initial setup guide with email configuration
- Stripe Setup — Payment integration that sends confirmation emails
- PayPal Setup — Alternative payment integration with email notifications
- Environment Variables — Complete environment configuration reference