SMTP Configuration Tutorial: Building Your Email Sending System from Scratch
SMTP (Simple Mail Transfer Protocol) is the standard protocol for sending email on the internet. This article covers two approaches: using third-party services (recommended) and self-hosting.
1. SMTP Basics
1.1 SMTP Ports
| Port | Encryption | Notes |
|---|---|---|
| 25 | None/STARTTLS | Traditional, often blocked |
| 465 | SSL/TLS | SMTPS, recommended |
| 587 | STARTTLS | Submission port, recommended |
Use port 587 (STARTTLS) or 465 (SSL). Port 25 is often blocked by ISPs.
2. Using Third-Party Email Services (Recommended)
2.1 Provider SMTP Configs
| Provider | Server | Port | Auth |
|---|---|---|---|
| SendGrid | smtp.sendgrid.net | 587/465 | API Key |
| Mailgun | smtp.mailgun.org | 587/465 | Login+Password |
| Resend | smtp.resend.com | 587/465 | API Key |
| Amazon SES | email-smtp.region.amazonaws.com | 587/465 | SMTP credentials |
2.2 Node.js + Nodemailer
const nodemailer = require('nodemailer');
const transporter = nodemailer.createTransport({
host: 'smtp.sendgrid.net',
port: 587,
auth: {
user: 'apikey',
pass: process.env.SENDGRID_API_KEY,
},
});
await transporter.sendMail({
from: '"App" <[email protected]>',
to: '[email protected]',
subject: 'Password Reset',
html: `<p>Click to reset: <a href="${resetLink}">Reset</a></p>`,
});
2.3 Laravel (.env)
MAIL_MAILER=smtp
MAIL_HOST=smtp.sendgrid.net
MAIL_PORT=587
MAIL_USERNAME=apikey
MAIL_PASSWORD=SG.xxxxx
MAIL_ENCRYPTION=tls
[email protected]
3. Self-Hosting (Advanced)
3.1 Postfix + Dovecot
apt update && apt install postfix dovecot-core dovecot-imapd
postconf -e 'myhostname = mail.yourdomain.com'
systemctl restart postfix
3.2 Self-Hosted vs Third-Party
| Dimension | Self-Hosted | Third-Party |
|---|---|---|
| Cost | Server only | Per-volume or monthly |
| Deliverability | Lower (need IP warm-up) | High (shared IP reputation) |
| Control | Full | Limited |
| Maintenance | High | Low |
4. Best Practices
4.1 Error Handling with Retry
async function sendWithRetry(emailData, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await transporter.sendMail(emailData);
} catch (error) {
if (attempt === maxRetries) throw error;
await new Promise(r => setTimeout(r, Math.pow(2, attempt) * 1000));
}
}
}
4.2 Queue Processing
Use message queues (Bull, RabbitMQ) for high-volume sending.
5. Common Issues
| Issue | Cause | Fix |
|---|---|---|
| Timeout | Port blocked | Try 587 or 465 |
| Auth failed | Wrong API key | Check permissions |
| Rejected (550) | Low IP reputation | Configure SPF/DKIM |
| Spam folder | Content issues | Optimize content |
6. Summary
For most applications, use third-party SMTP (SendGrid/Mailgun/Resend) with proper SPF/DKIM/DMARC. Self-host only for special needs (data compliance, millions of emails/month).