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).