Quick SMTP Setup: From DNS to First Email in 10 Minutes
A hands-on walkthrough of SMTP integration for Django, Rails, Node.js, and more — covering DNS records, credentials, code examples in four languages, common error codes, and production readiness.
On this page · 11
If your application or framework already speaks SMTP — Django, Rails, Express, WordPress, Postfix as a relay — adding transactional email is usually a 10-minute job. Verify a sending domain, create credentials, plug them into your config, and send a test. That’s it.
This guide is a hands-on walkthrough covering the four steps to a working setup, what each DNS record does, common error codes with their fixes, code examples in four languages, and a production-readiness checklist.
SMTP vs API: When to Use Which
SMTP and REST are two different on-ramps to the same email infrastructure. Each has its niche.
SMTP vs REST API
Choose the right on-ramp for your use case
- Framework already has SMTP support (Django, Rails, WordPress, Laravel)
- Integrating a legacy system that does not speak REST
- System-level relay via Postfix or Sendmail
- Goal is working email in under 10 minutes
- Zero new dependencies — just plug in host, port, credentials
- Need idempotency keys to prevent duplicate sends
- Want fine-grained webhook-driven event handling
- Building greenfield — no legacy SMTP baggage
- Need bulk-batch operations at high volume
- Want server-side templates referenced by ID
- Need precise per-service API key scoping
The hybrid case is common. SMTP for legacy flows, REST for new ones. Both share the same verified sending domain, suppression list, and analytics — no parallel infrastructure.
If your goal is “first email in 10 minutes,” SMTP is usually the faster path. The hybrid case is also common — SMTP for the legacy parts of your stack, REST for new transactional flows. Both can run side by side on the same verified sending domain.
The 4-Step Flow
The whole SMTP setup boils down to four steps:
- Verify your sending domain — add DNS records so receiving servers trust your emails.
- Create SMTP credentials — a username and password from the Brixus365 dashboard.
- Configure your application — plug the host, port, and credentials into your framework.
- Send a test and check the headers — confirm DKIM, SPF, and DMARC all pass.
SMTP Setup at a Glance
Four steps from zero to authenticated sends
Verify Sending Domain
Add SPF, DKIM, and DMARC DNS records at your registrar
Create SMTP Credentials
Dashboard → Settings → Developer → SMTP Credentials → New
Configure Your App
Set SMTP host, port 587, username, and password from env vars
Send Test & Verify Headers
Check DKIM, SPF, and DMARC all show "pass" in raw headers
10 min
total setup
587
recommended port
3
auth checks pass
Most of the time is spent waiting for DNS to propagate (typically minutes, occasionally up to an hour). Everything else takes seconds.
Step 1: Verify Your Sending Domain
Before you can send from you@yourdomain.com, you need to prove to the world that you control yourdomain.com. This is done with a few DNS records you add once and then forget.
DNS Records for SMTP
Brixus365 generates all values — just copy and paste into your registrar
Record Type
TXTHost / Name
@ (yourdomain.com)Value
v=spf1 include:spf.brixus365.com -allDeclares which mail servers are authorised to send on behalf of your domain. The -all suffix means hard-fail for any unlisted server.
Record Type
CNAMEHost / Name
brixus365._domainkeyValue
brixus365._domainkey.brixus365.comDelegates DKIM key management to Brixus365 via CNAME. Two records required — the dashboard shows both with copy-to-clipboard buttons.
Record Type
TXTHost / Name
_amazonses.yourdomain.comValue
brixus365-verify=<token>One-time record that proves domain ownership to the sending infrastructure. Generated automatically by Brixus365.
Record Type
TXTHost / Name
_dmarc.yourdomain.comValue
v=DMARC1; p=none; rua=mailto:dmarc-reports@yourdomain.comTells receiving servers what to do when SPF or DKIM fails, and enables aggregate reporting. Start with p=none, tighten after 30–60 days.
Tip: Brixus365 generates the exact record values with copy-to-clipboard buttons after you add your domain in Settings → Email Setup.
A note on SPF merging
SPF allows only one TXT record per domain. If you already have an SPF record for Google Workspace, Zoho, or another provider, do not create a second one — merge the includes:
v=spf1 include:_spf.google.com include:spf.brixus365.com -all
DMARC: start at p=none
Even though DMARC is recommended rather than required, set it up from day one. Start permissive:
v=DMARC1; p=none; rua=mailto:dmarc-reports@yourdomain.com
p=none means failing mail is still delivered — you are monitoring, not enforcing. After 30–60 days of clean reports, advance to p=quarantine, then p=reject.
Step 2: Create SMTP Credentials
Navigate to Settings → Developer → SMTP Credentials → New Credential in the Brixus365 dashboard.
You will get back four values:
| Field | Value |
|---|---|
| Host | smtp.brixus365.com |
| Port | 587 (STARTTLS) or 465 (Implicit TLS) |
| Username | Your domain’s user identifier |
| Password | Shown once at creation — copy it now |
Port 587 vs 465
- Port 587 (STARTTLS): the modern standard. The connection starts unencrypted, then upgrades to TLS. Most libraries default here.
- Port 465 (Implicit TLS): TLS from the first byte. Older standard, still widely supported.
Use port 587 for new setups. If your library only supports 465, that is also fine — both ports terminate at the same backend.
Step 3: Configure Your Application
Here are minimum working configurations for the four most common environments. More languages in the Code Examples section below.
Framework Quick-Start
Minimum config to send your first email via SMTP
import nodemailer from "nodemailer";
const transporter = nodemailer.createTransport({
host: "smtp.brixus365.com",
port: 587,
secure: false, // STARTTLS
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS,
},
});
await transporter.sendMail({
from: '"YourBrand Orders" <orders@yourdomain.com>',
to: "customer@example.com",
subject: "Your order is confirmed",
text: "Hi Aarav, thanks for your order.",
html: "<p>Hi Aarav, thanks for your order.</p>",
});Pro tip (Node.js): Add pool: true and maxConnections: 5 for production throughput.
Postfix as a relay
For system-level email from a Linux server, configure Postfix in /etc/postfix/main.cf:
relayhost = [smtp.brixus365.com]:587
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_use_tls = yes
smtp_tls_security_level = encrypt
Then create /etc/postfix/sasl_passwd:
[smtp.brixus365.com]:587 username:password
Run postmap /etc/postfix/sasl_passwd, then reload Postfix with systemctl reload postfix.
Step 4: Send a Test and Verify in Your Inbox
Send a message from your code to your own email address, then open it and check three things.
1. Check the authentication headers. In Gmail, click ⋮ → “Show original”. You should see:
Authentication-Results: mx.google.com;
dkim=pass header.i=@yourdomain.com header.s=brixus365
spf=pass smtp.mailfrom=bounces@brixus365.com
dmarc=pass (p=NONE sp=NONE) header.from=yourdomain.com
All three must say pass. If any say fail or softfail, the DNS records are off — check propagation and re-verify.
2. Check delivery latency. A correctly configured transactional send arrives in under 5 seconds. Delays beyond 30 seconds indicate queuing problems — check the Brixus365 dashboard for message status.
3. Check the webhook event. If you have configured a webhook for email.delivered, you should see a matching event at your endpoint within seconds.
Common SMTP Errors
SMTP errors come back as status codes. The first digit tells you the broad meaning: 2xx = success, 4xx = temporary (retry), 5xx = permanent (fix something first).
SMTP Response Codes
The first digit tells you whether to retry, fix, or do nothing
2xx
Success
4xx
Temporary — retry
5xx
Permanent — fix first
TLS handshake failures present as connection errors before any SMTP response. Verify your library supports STARTTLS on port 587 and is not falling back to plaintext.
Code Examples
Beyond the framework integrations above, here are raw SMTP examples in Python and Go.
Python (smtplib):
import smtplib, os
from email.mime.text import MIMEText
msg = MIMEText("Hi Aarav, thanks for your order.")
msg["From"] = "orders@yourdomain.com"
msg["To"] = "customer@example.com"
msg["Subject"] = "Your order is confirmed"
with smtplib.SMTP("smtp.brixus365.com", 587) as s:
s.starttls()
s.login(os.environ["SMTP_USER"], os.environ["SMTP_PASS"])
s.send_message(msg)
Go (net/smtp):
auth := smtp.PlainAuth("", os.Getenv("SMTP_USER"), os.Getenv("SMTP_PASS"), "smtp.brixus365.com")
to := []string{"customer@example.com"}
msg := []byte(
"From: orders@yourdomain.com\r\n" +
"To: customer@example.com\r\n" +
"Subject: Your order is confirmed\r\n\r\n" +
"Hi Aarav, thanks for your order.\r\n",
)
err := smtp.SendMail("smtp.brixus365.com:587", auth, "orders@yourdomain.com", to, msg)
Ruby (Mail gem):
Mail.defaults do
delivery_method :smtp, {
address: "smtp.brixus365.com",
port: 587,
user_name: ENV["SMTP_USER"],
password: ENV["SMTP_PASS"],
enable_starttls_auto: true,
}
end
Mail.deliver do
from "orders@yourdomain.com"
to "customer@example.com"
subject "Your order is confirmed"
body "Hi Aarav, thanks for your order."
end
Production Readiness
The basic setup gets you working. Production-ready needs a few more things.
Production Readiness Checklist
Check off each item before going live at scale
0/13
complete
Connection pooling enabled
Reuse TCP+TLS connections instead of opening one per message (saves 100–500 ms each).
maxConnections tuned for your volume
Too few = bottleneck. Too many = rate-limited. Start with 5 and adjust based on throughput.
Idle connection timeout configured
Stale connections cause silent send failures. Set idleTimeout to less than the server-side keepalive limit.
Exponential backoff for 4xx errors
Schedule: 1s → 5s → 30s → 2min → 10min. Never retry 5xx without fixing the cause first.
Max retry cap (5 attempts)
Infinite retries fill queues and mask bugs. Cap at 5, then dead-letter.
Dead-letter queue for permanent failures
Failed messages must go somewhere visible, not silently drop. Route to a DLQ and alert.
Sends decoupled from HTTP request threads
Enqueue the job in the HTTP request, send in a worker. Never block a web request on SMTP.
Queue depth monitored with alerting
A growing queue means workers cannot keep up. Alert before the backlog becomes a delay for end-users.
Worker concurrency matches pool size
One worker + maxConnections=1 bottlenecks. Scale workers proportionally to connection pool.
Logging: message ID, recipient, status, retry count
Minimum structured log per send. This data resolves 90% of support escalations.
Alert on send success rate < 99%
Something is wrong upstream. Page on-call before customers report missing emails.
Alert on elevated 4xx rate
A spike means rate-limiting or a temporary backend issue. Investigate before retries exhaust.
Webhook events captured for delivered/bounced
SMTP success ≠ inbox delivery. Subscribe to delivered and bounced events from the dashboard.
Connection pooling
Opening a fresh SMTP connection per message adds 100–500 ms per send (TCP + TLS + AUTH). Reuse connections:
- Nodemailer: enable
pool: trueand tunemaxConnections. - Python smtplib: keep the
SMTPinstance alive across multiple sends. - Postfix as relay: handled automatically.
Retries with exponential backoff
SMTP 4xx errors are temporary — retry with a schedule like 1s → 5s → 30s → 2min → 10min. Cap at 5 attempts; after that, route to a dead-letter queue and alert.
Queue and dead-letter handling
For high-volume systems, decouple the send from the HTTP request. The HTTP request enqueues a job; a worker dequeues and sends. Failed jobs after N retries go to a dead-letter queue for manual review.
When to Switch to the API
SMTP is the right choice for many use cases — forever. But there are signals you have outgrown it:
- You need idempotency keys — SMTP has no native idempotency. Retries can duplicate sends.
- You want fine-grained per-message webhooks — possible with SMTP but more setup than via the API.
- You need high-volume batch operations — 10,000 transactional emails via SMTP one connection at a time is slower than a single API batch call.
- You want server-side templates referenced by ID — cleaner via API than via SMTP X-Headers.
- You want per-service key scoping — API keys can be scoped precisely; SMTP credentials are coarser.
The migration path is gradual: keep SMTP for legacy flows, route new flows through the API. The verified domain, suppression list, and webhook destinations are shared — there is no parallel infrastructure to maintain.
Key Takeaways
- SMTP gets you to first email in 10 minutes if your framework already supports it. Do not over-engineer with a custom API integration if SMTP works.
- Use port 587 with STARTTLS for new setups. Port 465 is fine but only default to it if your library requires it.
- Connection pooling and retries are not optional in production. Build them from day one, or debug them at 3 AM when your queue depth spikes.
FAQ
Should I use port 587 or 465 for SMTP?
Should I use SMTP or the email API?
Which frameworks can send through Brixus365 SMTP?
Is sending email through Brixus365 free?
Ready to send? Start free — 9,000 emails a month, no credit card — and point your app at SMTP in the next 10 minutes.
Send smarter emails with Brixus365
Campaigns and transactional API on one engine. 9,000 emails/month free, no credit card.