Zapmail requires specific environment variables to connect the backend SMTP server, frontend web interface, and PostgreSQL database.
Backend environment variables
The Go SMTP server requires these environment variables:
PORT
The TCP port number for the SMTP server to listen on.
Usage in code (backend/main.go:40-43):
port := os . Getenv ( "PORT" )
if port == "" {
log . Fatal ( "PORT environment variable not set" )
}
Example values :
2525 - Standard alternative SMTP port (recommended)
25 - Standard SMTP port (requires root on Linux)
587 - Submission port
Any custom port number
The server will fail to start if PORT is not set. This is a required environment variable.
SUPABASE_CONN_STRING
PostgreSQL connection string for database access.
Usage in code (backend/main.go:174-183):
func connectDB () * sql . DB {
connStr := os . Getenv ( "SUPABASE_CONN_STRING" )
db , err := sql . Open ( "postgres" , connStr )
if err != nil {
log . Fatal ( "Error connecting to DB:" , err )
}
if err := db . Ping (); err != nil {
log . Fatal ( "Cannot ping DB:" , err )
}
return db
}
Format :
postgresql://username:password@host:port/database?options
Example values :
Supabase
Local PostgreSQL
Railway PostgreSQL
With SSL mode
SUPABASE_CONN_STRING = "postgresql://postgres:[YOUR-PASSWORD]@db.[PROJECT-REF].supabase.co:5432/postgres"
Despite the variable name containing “SUPABASE”, this can be any PostgreSQL connection string, not just Supabase.
Frontend environment variables
The Next.js web interface requires these environment variables:
DATABASE_URL
PostgreSQL connection string for the frontend database connection pool.
Usage in code (ui/src/lib/db.ts:1-6):
import { Pool } from "pg" ;
export const db = new Pool ({
connectionString: process . env . DATABASE_URL ,
});
Format :
postgresql://username:password@host:port/database?options
The DATABASE_URL should point to the same PostgreSQL database as SUPABASE_CONN_STRING in the backend.
Example values :
Supabase
Local development
Production
DATABASE_URL = "postgresql://postgres:[YOUR-PASSWORD]@db.[PROJECT-REF].supabase.co:5432/postgres"
Configuration files
Backend .env file
Create a .env file in the backend directory:
# SMTP Server Port
PORT = 2525
# PostgreSQL Connection String
SUPABASE_CONN_STRING = postgresql://user:password@host:port/database
The backend uses github.com/joho/godotenv to load environment variables from .env (backend/main.go:28-33):
func init () {
err := godotenv . Load ()
if err != nil {
log . Println ( "No .env file found" )
}
}
If no .env file is found, the server will log a warning but continue if environment variables are set through other means (system environment, Docker, etc.).
Frontend .env.local file
Create a .env.local file in the ui directory:
# PostgreSQL Connection String
DATABASE_URL = postgresql://user:password@host:port/database
Never commit .env or .env.local files to version control. Add them to .gitignore.
Database schema
Both backend and frontend require the following PostgreSQL table:
CREATE TABLE emails (
id SERIAL PRIMARY KEY ,
username VARCHAR ( 255 ) NOT NULL ,
recipient VARCHAR ( 255 ) NOT NULL ,
raw_data TEXT NOT NULL ,
received_at TIMESTAMP NOT NULL
);
Column descriptions :
id - Auto-incrementing primary key
username - Extracted from email recipient (part before @)
recipient - Full recipient email address
raw_data - Complete raw email content including headers
received_at - Timestamp when email was received
Usage in code (backend/main.go:186-193):
func storeEmail ( db * sql . DB , email Email ) error {
query := `
INSERT INTO emails (username, recipient, raw_data, received_at)
VALUES ($1, $2, $3, $4)
`
_ , err := db . Exec ( query , email . Username , email . Recipient , email . RawData , email . ReceivedAt )
return err
}
Advanced configuration
Connection pool settings
For production deployments, you may want to configure the PostgreSQL connection pool in the frontend:
import { Pool } from "pg" ;
export const db = new Pool ({
connectionString: process . env . DATABASE_URL ,
max: 20 , // Maximum pool size
idleTimeoutMillis: 30000 , // Close idle clients after 30 seconds
connectionTimeoutMillis: 2000 , // Return error after 2 seconds if no connection available
});
SMTP server customization
The SMTP server behavior is configured in code. To customize:
Cleanup interval (backend/main.go:197):
// Change cleanup frequency from 1 hour to custom value
ticker := time . NewTicker ( 1 * time . Hour )
Email retention period (backend/main.go:200):
// Change from 7 days to custom retention
db . Exec ( `DELETE FROM emails WHERE received_at < NOW() - INTERVAL '7 days'` )
Welcome message (backend/main.go:71):
// Customize SMTP greeting
writer . WriteString ( "220 Welcome to Temporary Mail Service \r\n " )
Next.js configuration
The Next.js configuration can be extended in ui/next.config.ts:
import type { NextConfig } from "next" ;
const nextConfig : NextConfig = {
images: {
domains: [ "upload.wikimedia.org" ],
},
// Add custom configuration
output: 'standalone' , // For Docker deployments
poweredByHeader: false , // Remove X-Powered-By header
compress: true , // Enable gzip compression
};
export default nextConfig ;
Vercel
Add environment variables in the Vercel dashboard:
Go to Project Settings > Environment Variables
Add DATABASE_URL with your PostgreSQL connection string
Select appropriate environments (Production, Preview, Development)
Railway
Railway can auto-provision PostgreSQL:
Add PostgreSQL plugin to your project
Railway automatically provides DATABASE_URL
For backend, add PORT and SUPABASE_CONN_STRING (use Railway’s DATABASE_URL)
Docker Compose
Example configuration with all services:
version : '3.8'
services :
postgres :
image : postgres:16-alpine
environment :
POSTGRES_DB : zapmail
POSTGRES_USER : zapmail
POSTGRES_PASSWORD : changeme
volumes :
- postgres_data:/var/lib/postgresql/data
ports :
- "5432:5432"
backend :
build : ./backend
environment :
PORT : 2525
SUPABASE_CONN_STRING : postgresql://zapmail:changeme@postgres:5432/zapmail
ports :
- "2525:2525"
depends_on :
- postgres
frontend :
build : ./ui
environment :
DATABASE_URL : postgresql://zapmail:changeme@postgres:5432/zapmail
ports :
- "3000:3000"
depends_on :
- postgres
volumes :
postgres_data :
Security best practices
Use strong database passwords
Generate secure passwords for PostgreSQL users:
Enable SSL for database connections
Add ?sslmode=require to connection strings: DATABASE_URL = "postgresql://user:pass@host:5432/db?sslmode=require"
Restrict database access
Configure PostgreSQL to only accept connections from your application servers.
Use environment-specific variables
Never use production credentials in development environments.
Rotate credentials regularly
Update database passwords and connection strings periodically.
Troubleshooting
Environment variable not found
If you see “PORT environment variable not set”:
Check the variable is defined in .env or system environment
Ensure variable names match exactly (case-sensitive)
Restart the application after changing environment variables
Database connection failed
If you see “Error connecting to DB” or “Cannot ping DB”:
Verify the connection string format is correct
Test the connection with psql:
psql "postgresql://user:password@host:port/database"
Check network access and firewall rules
Verify database credentials are correct
Frontend can’t read environment variables
In Next.js:
Server-side variables (like DATABASE_URL) are only available in API routes and server components
Client-side variables must be prefixed with NEXT_PUBLIC_
Restart the dev server after changing .env.local
The DATABASE_URL is server-side only and cannot be accessed from client components.
Next steps
Backend setup Deploy the Go SMTP server
Frontend setup Deploy the Next.js interface