Summary: Email yang gagal terkirim karena throttling bukan masalah SMTP konfigurasi, tapi masalah kecepatan pengiriman yang melampaui batas provider. Rate limiting di level aplikasi mencegah error 421 dan soft bounce yang merusak reputasi domain. Artikel ini membahas implementasi praktis dengan contoh kode di Laravel, Node.js, dan Python.
Developer sering mengira kalau email gagal terkirim, masalahnya ada di konfigurasi SMTP. Host salah, port salah, atau authentication bermasalah. Tapi ada satu kategori error yang sering terlewat: throttling dari provider email tujuan.
Error 421 dari Gmail, soft bounce dari Outlook, atau email yang queued terlalu lama di log SMTP: semuanya bisa jadi tanda kalau kecepatan pengiriman Anda melampaui batas yang diterima provider. Dan provider tidak akan memberitahu Anda secara eksplisit. Mereka cuma menolak email dan menunggu Anda menyesuaikan.
Daftar Isi
Apa Itu Email Rate Limiting dan Kenapa Provider Melakukannya?
Rate limiting adalah mekanisme provider email untuk membatasi jumlah email yang bisa diterima dalam periode waktu tertentu. Gmail membatasi sekitar 2.000 email per hari untuk akun Workspace. Outlook punya batasan serupa. Provider lain punya masing-masing threshold yang berbeda.
Ini bukan untuk menyulitkan developer. Rate limiting melindungi infrastruktur provider dari spam flood dan menjaga kualitas layanan untuk semua pengguna.
Kalau Anda mengirim 10.000 email dalam 1 jam ke domain Gmail, Gmail akan mulai menolak email Anda dengan error 421. Bukan karena email Anda spam, tapi karena volume melampaui kapasitas yang mereka tolerir per sender. Kalau ini terus berlanjut, reputasi domain Anda turun dan email Anda bisa masuk spam.
Throttling dalam email sending adalah istilah yang sering dipakai untuk kondisi ini. Provider memperlambat atau menolak email sementara untuk memberi ruang infrastruktur mereka recovery.
Error 421: Tanda Paling Umum Rate Limit Terlampaui
Error 421 adalah SMTP response code yang menunjukkan temporary failure. Bukan permanent failure seperti 5xx yang berarti email tidak akan pernah berhasil. Tapi transient failure: server tidak bisa memproses saat ini, coba lagi nanti.
Beberapa varian error 421 yang sering muncul:
421-4.4.5 Serverbusy: Server penerima sedang overload atau rate limit aktif. Coba lagi dengan interval yang lebih lambat.
421-4.7.0 Rate limit exceeded: Pengirim melebihi batas pengiriman yang diizinkan provider. Tunggu beberapa jam sebelum retry.
421 4.7.1 Connection rate limit exceeded: Terlalu banyak koneksi SMTP dalam waktu singkat. Provider mendeteksi perilaku spam-like.
Error 421 adalah transient. Email Anda tidak hilang. Tapi kalau aplikasi Anda tidak handle dengan benar, email bisa hilang dari queue tanpa disadari atau di-retry terlalu agresif dan justru memperburuk reputasi.
Perbedaan Rate Limiting dari Sisi Sender dan Receiver
Ada dua perspektif rate limiting yang sering dicampur.
Throttling dari sisi receiver adalah ketika provider email tujuan (Gmail, Outlook, Yahoo) membatasi email yang Anda kirim. Anda tidak punya kontrol langsung. Yang bisa Anda lakukan adalah mengurangi kecepatan pengiriman di sisi aplikasi supaya tidak memicu throttling.
Throttling dari sisi sender adalah ketika SMTP provider Anda membatasi kecepatan pengiriman. Contoh: AWS SES punya limit per detik. Kalau Anda kirim melebihi limit, SES akan menolak email sebelum sampai ke provider tujuan.
Keduanya butuh penanganan berbeda. Untuk throttling dari receiver, Anda perlu rate limiting di level aplikasi. Untuk throttling dari sender, Anda perlu memilih plan yang sesuai atau menghubungi provider untuk increase limit.
Bounce Rate dan Hubungannya dengan Rate Limiting
Bounce rate adalah persentase email yang gagal terkirim. Bounce rate yang sehat di bawah 2 persen. Kalau bounce rate Anda naik di atas 5 persen, provider akan mulai menurunkan reputasi domain Anda.
Soft bounce akibat rate limiting terus-menerus akan menaikkan bounce rate. Provider tidak membedakan apakah soft bounce itu karena inbox penuh, server sibuk, atau throttling. Dari sudut pandang mereka, jika email Anda sering gagal, ada yang salah dengan praktik pengiriman Anda.
Bounce rate email yang tinggi bisa dicegah dengan rate limiting yang tepat. Bukan cuma mengandalkan retry mechanism, tapi mencegah soft bounce sejak awal dengan kontrol volume pengiriman.
Implementasi Rate Limiting di Laravel
Laravel menyediakan Redis throttle method yang bisa dipakai untuk mengontrol kecepatan queue worker. Ini berguna ketika Anda mengirim email melalui queue dan ingin memastikan tidak melebihi batas tertentu per menit atau per detik.
Menggunakan Redis::throttle untuk Email Queue
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Mail;
class SendEmailJob implements ShouldQueue
{
use Queueable;
protected $email;
protected $recipient;
public function __construct($email, $recipient)
{
$this->email = $email;
$this->recipient = $recipient;
}
public function handle()
{
// Rate limit: 10 email per 60 detik
Redis::throttle('email-sending')
->allow(10)
->every(60)
->then(function () {
Mail::to($this->recipient)->send($this->email);
}, function () {
// Kalau rate limit tercapai, release job kembali ke queue
$this->release(10);
});
}
}
Method throttle menggunakan Redis sebagai backend. Setiap kali job dieksekusi, Redis mencatat berapa kali key email-sending diakses dalam window60 detik terakhir. Kalau sudah mencapai 10, job akan di-release kembali ke queue dengan delay 10 detik.
Dispatch Job dengan Rate Limiting
use App\Jobs\SendEmailJob;
// Dispatch ke queue dengan rate limiting otomatis
SendEmailJob::dispatch($email, '[email protected]');
Pastikan queue worker berjalan dan Redis terkonfigurasi dengan benar di config/database.php. Untuk setup queue yang lebih detail, baca panduan cara mengirim email di Laravel dengan queue.
Implementasi Rate Limiting di Node.js dengan BullMQ
Node.js tidak punya built-in queue system. Salah satu opsi populer adalah BullMQ yang menyimpan job di Redis dan menyediakan rate limiting di level worker.
Setup Queue dengan Rate Limiter
const { Queue, Worker } = require('bullmq');
const nodemailer = require('nodemailer');
const emailQueue = new Queue('email-queue', {
connection: {
host: 'localhost',
port: 6379
}
});
const worker = new Worker('email-queue', async job => {
const { email, recipient } = job.data;
const transporter = nodemailer.createTransport({
host: 'smtp.kirim.email',
port: 587,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS
}
});
await transporter.sendMail({
from: process.env.EMAIL_FROM,
to: recipient,
subject: email.subject,
text: email.text,
html: email.html
});
}, {
connection: {
host: 'localhost',
port: 6379
},
limiter: {
max: 10, // Maksimal 10 job
duration: 60000 // Per 60 detik (dalam milidetik)
}
});
Konfigurasi limiter di BullMQ memastikan worker tidak memproses lebih dari 10 job dalam window 60 detik. Job yang melebihi limit akan di-queue otomatis tanpa perlu tambahan kode.
Menambah Job ke Queue
await emailQueue.add('send-email', {
email: {
subject: 'Welcome',
text: 'Hello!',
html: '<p>Hello!</p>'
},
recipient: '[email protected]'
});
BullMQ menyimpan job di Redis dan menjamin bahwa rate limit dipatuhi walau ada multiple worker instance.
Implementasi Rate Limiting di Python dengan Token Bucket
Python membutuhkan library tambahan atau implementasi manual untuk rate limiting. Algoritma yang paling umum adalah Token Bucket.
Token Bucket Algorithm untuk Email Sending
import time
from threading import Lock
class EmailRateLimiter:
def __init__(self, rate, capacity):
"""
Args:
rate: Token yang ditambahkan per detik
capacity: Maksimal token yang bisa disimpan
"""
self.rate = rate
self.capacity = capacity
self.tokens = capacity
self.last_update = time.time()
self.lock = Lock()
def _add_tokens(self):
"""Tambah token berdasarkan waktu yang berlalu"""
now = time.time()
elapsed = now - self.last_update
self.tokens = min(
self.capacity,
self.tokens + elapsed * self.rate
)
self.last_update = now
def acquire(self):
"""Ambil satu token, return True kalau berhasil"""
with self.lock:
self._add_tokens()
if self.tokens >= 1:
self.tokens -= 1
return True
return False
def wait_for_token(self):
"""Tunggu sampai token tersedia"""
while not self.acquire():
time.sleep(0.1)
# Penggunaan: 5 email per detik, burst maksimal 10
limiter = EmailRateLimiter(rate=5, capacity=10)
def send_email_with_rate_limit(smtp_client, email_data):
limiter.wait_for_token()
smtp_client.send_message(email_data)
Token Bucket bekerja dengan menyimpan token dalam bucket. Setiap kali email dikirim, satu token diambil. Token baru ditambahkan secara berkala sesuai rate yang dikonfigurasi. Jika bucket kosong, pengiriman harus menunggu sampai token tersedia.
Kapan Harus Stop Retry dan Anggap Gagal Permanen?
Rate limiting bukan berarti Anda harus terus retry tanpaampyung. Ada batasnya.
RFC 5321 menyebutkan kalau client wajib retry saat menerima error 4xx, tapi tidak boleh lebih dari 4 jam. Setelah 4 jam, email harus dianggap gagal dan dicatat sebagai bounce.
Beberapa guideline praktis:
Setelah5-7 retry: Jika semua retry gagal, kemungkinan besar bukan throttling sementara. Ada masalah lain seperti IP blacklist atau reputasi domain buruk.
Setelah bounce rate mencapai threshold: Jika bounce rate Anda sudah di atas 5 persen, stop sending sementara dan investigasi. Melanjutkan retry justru memperburuk reputasi.
Setelah menerima permanent error: Error 5xx seperti 550 Mailbox Not Found bukan throttling. Jangan retry. Catat sebagai hard bounce dan lanjut.
Monitoring yang Wajib Dipasang untuk Rate Limiting
Mengimplementasikan rate limiting tanpa monitoring adalah kerja buta. Anda tidak akan tahu apakah limit yang Anda set sudah tepat atau masih terlalu tinggi.
Metrik yang Harus Dipantau
Retry rate: Persentase email yang membutuhkan retry karena error 4xx. Normal jika di bawah 5 persen. Jika naik, mungkin kecepatan pengiriman perlu dikurangi.
Soft bounce rate: Persentase email yang gagal sementara. Soft bounce yang tinggi menandakan provider sedang throttling email Anda.
Time to delivery: Rata-rata waktu dari email masuk queue sampai berhasil terkirim. Jika meningkat signifikan, kemungkinan rate limit terlampaui.
Alert yang Perlu Disetup
// Laravel example: Alert jika retry rate tinggi
if ($retryRate > 0.05) {
Log::warning("High retry rate detected: {$retryRate}");
// Kirim notifikasi ke Slack atau Telegram
}
Untuk memahami lebih lanjut tentang monitoring email delivery, baca panduan cara test email deliverability.
Kalau reputasi IP atau domain sudah terlanjur buruk akibat throttling, Anda mungkin perlu melakukan IP warm-up. Baca panduan cara warm-up IPemail untuk memahami prosesnya.
Kalau implementasi rate limiting dari nol terasa kompleks, KIRIM.EMAIL Dev menyediakan infrastruktur dengan rate limiting otomatis dan monitoring real-time. Anda tidak perlu membangun queue system sendiri, cukup kirim lewat API dan sistem akan mengatur kecepatan pengiriman supaya tidak memicu throttling dari provider.
FAQ
Apa perbedaan rate limiting dan throttling dalam konteks email?
Rate limiting adalah mekanisme yang Anda terapkan di level aplikasi untuk membatasi kecepatan pengiriman. Throttling adalah tindakan yang dilakukan provider ketika menerima email melebihi kapasitas yang mereka tolerir. Rate limiting mencegah throttling.
Berapa batas email per hari yang aman untuk Gmail dan Outlook?
Gmail membatasi sekitar 2.000 email per hari untuk akun Google Workspace dan 500 email untuk akun personal. Outlook memiliki batasan serupa. Batas ini adalah rolling window, bukan reset setiap tengah malam.
Apakah queue worker di Laravel sudah menangani rate limiting otomatis?
Tidak otomatis. Laravel queue worker akan memproses job secepat mungkin. Untuk rate limiting, Anda perlu menambahkan Redis::throttle() di dalam job atau mengkonfigurasi queue worker dengan opsi –max-jobs dan –max-time.
Bagaimana cara mengetahui apakah email saya sedang di-throttle oleh provider?
Tanda paling umum adalah menerima response 421 dari server tujuan atau melihat email terqueued terlalu lama di log SMTP. Soft bounce rate yang meningkat juga indikator kuat.
Apa yang harus dilakukan kalau aplikasi sudah mengirim terlalu cepat dan reputasi domain turun?
Langkah pertama adalah stop sending sementara dan biarkan volume recovery. Kemudian implementasikan rate limiting dengan threshold konservatif, misalnya 5 email per menit. Perlahan-lahan tingkatkan setelah bounce rate normal. Kalau reputasi sudah parah, pertimbangkan untuk pindah ke dedicated IP baru dan lakukan IP warm-up.
Apakah dedicated IP mengatasi masalah rate limiting?
Dedicated IP memberikan kontrol penuh atas reputasi, tapi tidak menghilangkan batasan dari provider email tujuan. Gmail dan Outlook tetap akan throttle jika Anda mengirim terlalu cepat. Keuntungan dedicated IP adalah Anda tidak terdampak perilaku pengguna lain di shared IP.
Hasbi Putra adalah Head of Marketing di KIRIM.EMAIL, email delivery infrastructure untuk developer dan tim IT di Indonesia. KIRIM.EMAIL mengirim lebih dari 11 juta email per hari dengan server yang sepenuhnya berlokasi di Indonesia.
