CLI tool for managing custom domain email. Uses Cloudflare Email Routing for receiving and Brevo for sending.
Set up professional email for any domain in one command — no Google Workspace, no Fastmail, no monthly fees.
mailctl add yourdomain.com -a hello,support
That single command:
- Finds your Cloudflare zone
- Enables email routing with MX records
- Creates forwarding rules for each alias
- Enables catch-all forwarding
- Adds the domain to Brevo
- Creates SPF/DKIM DNS records
- Authenticates the domain for sending
- Creates sender addresses
- Prints Gmail Send-As setup instructions
go install github.com/sislelabs/mailctl@latestOr build from source:
git clone https://github.com/sislelabs/mailctl.git
cd mailctl
go build .# Interactive setup — configures API keys
mailctl init
# Set up email for a domain
mailctl add yourdomain.com -a hello,support
# Launch the TUI dashboard
mailctlmailctl # TUI dashboard
mailctl add yourdomain.com -a hello # Full email setup
mailctl list # List domains with live status
mailctl check yourdomain.com # Deep health check (routing, DNS, Brevo)
mailctl alias add yourdomain.com billing # Add an alias
mailctl alias list yourdomain.com # List aliases
mailctl alias catchall yourdomain.com on # Enable catch-all forwarding
mailctl remove yourdomain.com # Tear down everythingRun mailctl with no arguments for an interactive dashboard:
- Browse domains with live status
- Inspect domain health checks
- Manage aliases inline
- Run flows with
f
Flows are composable YAML workflows. Drop a .yaml file in ~/.mailctl/flows/ and it's automatically discovered.
mailctl flow list # See available flows
mailctl flow run <name> [args] [--flags] # Run a flow
mailctl flow new # Scaffold a new flowExample flow:
name: "welcome:send"
description: "Send welcome email to a new customer"
args:
- name: email
required: true
steps:
- step: email.send
args:
to: "{{.args.email}}"
subject: "Welcome!"
body: "Thanks for signing up."Available steps:
print— display styled outputexit— stop flow executionconfirm— type-to-confirm promptprompt— interactive input wizardconfig.load— load mailctl configemail.send— send email with optional attachments
Flow control: if/else conditionals, for_each iteration.
Stored at ~/.mailctl.yaml with 0600 permissions.
cloudflare_api_token: "cfut_..."
cloudflare_account_id: "abc123..."
brevo_api_key: "xkeysib-..."
brevo_smtp_key: "xsmtpsib-..."
brevo_smtp_login: "xxx@smtp-brevo.com"
default_forward_to: "you@gmail.com"
# Managed by mailctl add/remove — don't edit by hand
domains:
- domain: yourdomain.com
cloudflare_zone_id: "..."
aliases:
- alias: hello
forward_to: [you@gmail.com]
# For sending emails from flows
smtp:
host: "smtp-relay.brevo.com"
port: 587
user: "xxx@smtp-brevo.com"
pass: "xsmtpsib-..."
default_from: "hello@yourdomain.com"- Go 1.22+ — install Go
- A domain on Cloudflare — DNS must be managed by Cloudflare
- A Brevo account — free tier works, needed for SMTP sending
Create one at dash.cloudflare.com/profile/api-tokens with these permissions:
| Permission | Access |
|---|---|
| Zone > DNS | Edit |
| Zone > Email Routing Rules | Edit |
| Zone > Email Routing Addresses | Edit |
| Account > Email Routing Addresses | Read |
After mailctl add, you can send from your custom domain in Gmail:
- Open Gmail Accounts settings
- Click "Add another email address"
- Use the SMTP settings printed by
mailctl add
Emails not arriving after mailctl add
MX record propagation can take up to 15 minutes. Check with:
dig yourdomain.com MX +short
mailctl check yourdomain.com"Authentication error (code 10000)" from Cloudflare
Your API token is missing permissions. See the table above.
SMTP errors when sending from flows
Check the smtp section in ~/.mailctl.yaml. The user and pass fields use your Brevo SMTP credentials (different from the API key).
MIT

