Send and receive email from multiple domain identities through a single interface. Built on Next.js + Vercel + Brevo + Cloudflare Email Routing. Zero cost to run.
[Client UI] → [Next.js API on Vercel] → [Brevo SMTP] → recipient
recipient → [Cloudflare Email Routing] → [/api/inbound/receive webhook] → [Postgres]
git clone <your-repo>
cd multibrand-email
npm install- Go to vercel.com → Storage → Create → Postgres
- Connect to your project — it auto-populates env vars
- Or use Supabase free tier and copy the connection strings manually
- Sign up at brevo.com
- Go to SMTP & API → SMTP
- Copy your login email and generate an SMTP key
- Paste into
.env.localasBREVO_SMTP_USERandBREVO_SMTP_KEY
Verify your sender domains in Brevo:
- Go to Senders & IP → Domains → Add a domain
- For each domain (easonet.com, survivalstorehouse.com, etc.), add the SPF/DKIM records they give you
For domains already on Cloudflare:
- Go to your domain → Email → Email Routing
- Enable Email Routing — Cloudflare adds MX records automatically
- Add a catch-all rule: action = Send to a Worker or Forward to your webhook
For domains NOT on Cloudflare — move them, or use ImprovMX:
- Sign up at improvmx.com (free up to 25 domains)
- Add your domain, set MX records as instructed
- Forward all mail to your webhook URL (ImprovMX supports webhook forwarding on paid plan)
- Alternative: forward to a mailbox, then poll via IMAP (more complex)
Your inbound webhook endpoint is:
https://your-vercel-app.vercel.app/api/inbound/receive
Set a strong random secret:
openssl rand -hex 32Paste it as INBOUND_WEBHOOK_SECRET in your env vars, and set the same value as the
webhook secret header (x-webhook-secret) in your forwarding service config.
Brevo inbound webhook setup:
- Go to Inbound Parsing in Brevo
- Set your domain's MX to Brevo's inbound server
- Point the webhook to your
/api/inbound/receiveURL
Cloudflare Worker approach (most control): Create a Worker that forwards the raw email to your webhook:
export default {
async email(message, env) {
const raw = await new Response(message.raw).arrayBuffer()
await fetch('https://your-app.vercel.app/api/inbound/receive', {
method: 'POST',
headers: {
'Content-Type': 'message/rfc822',
'x-webhook-secret': env.WEBHOOK_SECRET,
'x-forwarded-to': message.to,
},
body: raw,
})
}
}npm install -g vercel
vercelAdd all env vars in Vercel dashboard → Settings → Environment Variables.
npx prisma db pushOpen the app, click + Add identity, enter name + email. Follow the DNS instructions shown in the modal.
- Add identity in the UI (name + email address)
- Add domain to Brevo sender verification
- Set DNS records on the domain:
- MX: point to Cloudflare Email Routing or ImprovMX
- SPF TXT:
v=spf1 include:_spf.brevo.com ~all - DKIM TXT: from Brevo domain verification page
- Done — emails sent from this identity will appear to come from that domain
When ready to move off free tiers:
| Current | Replace with |
|---|---|
| Brevo SMTP | Postal (self-hosted) or AWS SES |
| Cloudflare Email Routing | Postfix/Dovecot on a VPS |
| Vercel Postgres | Supabase Pro or self-hosted Postgres |
| Vercel API | Node.js on a VPS (same code, npm start) |
The API code doesn't change — just swap the env vars.
/pages
index.tsx — email client UI
/api
/identities
index.ts — GET list / POST create identity
/emails
send.ts — POST send email
threads.ts — GET list threads
/inbound
receive.ts — POST inbound webhook
/lib
prisma.ts — db client singleton
mailer.ts — nodemailer send wrapper
/prisma
schema.prisma — Identity, Thread, Message models