A self-hosted email management system built on Cloudflare Workers. Receive emails on your custom domain, store them in a database, and send emails through Brevo - all running on Cloudflare's edge network.
- Receive Emails: Use Cloudflare Email Routing to receive emails on your custom domain
- Send Emails: Send emails through Brevo's reliable SMTP API
- Attachment Support: Send and receive emails with attachments (up to 5MB per file)
- Modern UI: Vue 3 SPA with a clean, responsive interface
- Secure: PBKDF2 password hashing, rate limiting, security headers
- Serverless: Runs entirely on Cloudflare Workers with D1 database
- Optional Forwarding: Optionally forward received emails to your personal inbox
┌─────────────────────────────────────────────────────────────┐
│ Cloudflare Edge │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Email │ │ Worker │ │ D1 │ │
│ │ Routing │───▶│ (Hono) │◀──▶│ Database │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Incoming │ │ Vue SPA │ │
│ │ Emails │ │ (Frontend) │ │
│ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────┐
│ Brevo │
│ (Sending) │
└─────────────┘
Before you begin, make sure you have:
- Cloudflare Account with a domain added
- Brevo Account (free tier available at brevo.com)
- Node.js 18+ and pnpm installed
- Wrangler CLI installed (
npm install -g wrangler)
git clone https://github.com/MrOplus/AvaMail.git
cd AvaMail
pnpm installLogin to Wrangler:
wrangler loginCreate a D1 database:
cd packages/worker
wrangler d1 create avamail-dbCopy the example config and update with your database ID:
cp wrangler.toml.example wrangler.tomlThen edit wrangler.toml and replace YOUR_DATABASE_ID_HERE with the ID from the previous command:
[[d1_databases]]
binding = "DB"
database_name = "avamail-db"
database_id = "your-actual-database-id"Run the database migrations:
wrangler d1 execute avamail-db --remote --file=src/db/schema.sqlcd ../../frontend
pnpm run buildcd ../packages/worker
pnpm run deployYour application will be deployed to https://avamail.<your-subdomain>.workers.dev
The wrangler.toml file is gitignored to prevent accidentally committing your database ID. Copy the example file to get started:
cd packages/worker
cp wrangler.toml.example wrangler.tomlThe configuration file contains:
name = "avamail" # Worker name (can be customized)
main = "src/index.ts"
compatibility_date = "2024-01-01"
# D1 Database - Replace with your actual database ID
[[d1_databases]]
binding = "DB"
database_name = "avamail-db"
database_id = "YOUR_DATABASE_ID_HERE" # From: wrangler d1 create avamail-db
# Static assets from Vue build
[assets]
directory = "../../frontend/dist"
# Environment variables
[vars]
APP_NAME = "AvaMail"| Setting | Description | How to Get |
|---|---|---|
database_id |
Your D1 database UUID | Run wrangler d1 create avamail-db and copy the ID |
| Setting | Default | Description |
|---|---|---|
name |
avamail |
Worker name (affects the URL: name.subdomain.workers.dev) |
APP_NAME |
AvaMail |
Application display name |
Important: Never commit sensitive data to
wrangler.toml. API keys and secrets are stored securely in the D1 database after initial setup through the UI.
- Open your deployed application URL
- Create your admin password (minimum 8 characters)
- You'll be logged in automatically
-
Go to Settings → Cloudflare tab
-
Create a Cloudflare API Token with the required permissions:
Creating an API Token:
- Go to Cloudflare Dashboard → API Tokens
- Click Create Token
- Select Create Custom Token
- Add the following permissions:
Account Permissions:
Permission Access Level Email Routing Addresses Edit Zone Permissions:
Permission Access Level Zone Read DNS Edit Email Routing Rules Edit Zone Settings Edit - Set Zone Resources to:
Include→All zones(or select specific zone) - Set Account Resources to:
Include→ your account - Click Continue to summary → Create Token
- Copy the token (you won't see it again!)
-
Enter your Cloudflare credentials in AvaMail:
Field Description Where to Find API Token Custom API token Created above with required scopes Account ID Your account identifier Dashboard sidebar or any zone URL Domain Your email domain e.g., example.comForwarding Email (Optional) Backup email Your personal email for backup forwarding -
Click Save Cloudflare Settings
-
Click Fix Email Routing to ensure emails route to the worker
- Go to Settings → Brevo tab
- Get your Brevo API key:
- Log into Brevo
- Go to SMTP & API → API Keys
- Create a new API key or use existing one
- Enter your API key and save
To send emails from your domain:
- Go to Brevo Senders & Domains
- Add your domain
- Add the required DNS records (SPF, DKIM, DMARC)
- Verify the domain
- Go to Settings → Addresses tab
- Add email addresses you want to use (e.g.,
contact@yourdomain.com) - Set a default sending address
- Once Cloudflare and Brevo are configured, click Complete Setup
- You're ready to send and receive emails!
For email to work properly, ensure these DNS records are set:
Cloudflare will automatically configure these, but verify:
| Type | Name | Value | Priority |
|---|---|---|---|
| MX | @ | route1.mx.cloudflare.net |
69 |
| MX | @ | route2.mx.cloudflare.net |
15 |
| MX | @ | route3.mx.cloudflare.net |
21 |
| TXT | @ | v=spf1 include:_spf.mx.cloudflare.net ~all |
- |
Add the records provided by Brevo for your domain:
| Type | Name | Purpose |
|---|---|---|
| TXT | @ | SPF record |
| TXT | mail._domainkey | DKIM record |
| TXT | _dmarc | DMARC record |
Emails sent to any address at your domain (e.g., anything@yourdomain.com) will be:
- Received by Cloudflare Email Routing
- Processed by the worker
- Stored in the D1 database
- (Optional) Forwarded to your personal email
- Click Compose in the sidebar
- Select your "From" address
- Enter recipient, subject, and message
- Add attachments if needed (max 5MB per file, 10MB total)
- Click Send
- Inbox: View received emails
- Sent: View sent emails
- Star: Mark important emails
- Delete: Remove emails
# Start frontend dev server
cd frontend
pnpm run dev
# In another terminal, start worker dev server
cd packages/worker
pnpm run devAvaMail/
├── frontend/ # Vue 3 SPA
│ ├── src/
│ │ ├── api/ # API client
│ │ ├── stores/ # Pinia stores
│ │ ├── views/ # Page components
│ │ └── router/ # Vue Router
│ └── dist/ # Built assets
│
├── packages/
│ ├── worker/ # Cloudflare Worker
│ │ ├── src/
│ │ │ ├── api/ # API routes
│ │ │ ├── db/ # Database queries
│ │ │ ├── lib/ # Utilities
│ │ │ └── email-handler.ts
│ │ └── wrangler.toml
│ │
│ ├── cloudflare-email-api/ # Cloudflare API wrapper
│ └── mailgun-api/ # Brevo API wrapper
│
└── README.md
- PBKDF2 Password Hashing: 100,000 iterations with SHA-256
- Rate Limiting: Login attempts limited to 5 per 15 minutes
- Security Headers: X-Frame-Options, X-Content-Type-Options, etc.
- Session Management: Secure token-based authentication
- Input Validation: All inputs validated and sanitized
- Timing-Safe Comparisons: Prevents timing attacks
For production use:
- Custom Domain: Use your own domain instead of
workers.dev - HTTPS Only: Cloudflare Workers are HTTPS by default
- Strong Password: Use a strong, unique admin password
- Regular Updates: Keep dependencies updated
- Backup: Regularly export your D1 database
- Verify DNS records are correct
- Check Cloudflare Email Routing is enabled
- Click Fix Email Routing in Settings → Cloudflare
- Check the worker logs:
wrangler tail
- Verify Brevo API key is correct
- Ensure your domain is verified in Brevo
- Check sender address is added to Brevo senders
- Clear browser cache and cookies
- If locked out, wait 15 minutes for rate limit reset
- For password reset, manually update D1 database
- Login: 5 attempts per 15 minutes
- Setup: 3 attempts per hour
- Wait for the specified time before retrying
| Endpoint | Method | Description |
|---|---|---|
/api/auth/status |
GET | Check auth status |
/api/auth/login |
POST | Login with password |
/api/auth/logout |
POST | Logout |
/api/auth/setup |
POST | Initial password setup |
/api/auth/change-password |
POST | Change password |
| Endpoint | Method | Description |
|---|---|---|
/api/emails |
GET | List emails |
/api/emails/stats |
GET | Get email statistics |
/api/emails/:id |
GET | Get single email |
/api/emails/send |
POST | Send email |
/api/emails/:id/attachments/:attachmentId |
GET | Download attachment |
| Endpoint | Method | Description |
|---|---|---|
/api/setup/status |
GET | Get setup status |
/api/setup/cloudflare |
POST | Configure Cloudflare |
/api/setup/brevo |
POST | Configure Brevo |
/api/setup/cloudflare/worker-routing |
POST | Fix email routing |
MIT License - See LICENSE file for details.
For issues and feature requests, please visit GitHub Issues.