ارسال ایمیل از برنامههای self-hosted بدون میل سرور
برای ارسال ایمیل از برنامههای self-hosted نیازی به راهاندازی میل سرور نیست. با تنظیم یک SMTP relay در سطح هاست و پیکربندی SPF، DKIM و DMARC، مشکل مسدود بودن پورت 25 را حل کنید.
چه برنامههای self-hostedای نیاز به ارسال ایمیل دارند
برای ارسال ایمیل از برنامههای self-hosted نیازی به داشتن یک mail server کامل ندارید. شما به یک relay نیاز دارید: یک حساب SMTP احراز هویتشده که یکبار روی میزبان پیکربندی میشود و تمام برنامههای موجود روی آن سیستم، ایمیلهای خروجی خود را به آن میسپارند. راهاندازی و نگهداری یک mailbox، مسئلهای دشوار و کاملاً متفاوت است.
دریافت ایمیل به معنای پذیرش اتصالات از سراسر اینترنت روی پورت 25، فیلتر کردن هرزنامهها، ذخیرهسازی و پشتیبانگیری از صندوقهای پستی، و حفظ اعتبار IP سرور در تمام طول عمر آن است. این وظیفه بهطور واقعی دشوارتر شده است. ارسال ایمیل به معنای ارسال لینک بازنشانی رمز عبور، تأییدیه ثبتنام، هشدارهای «شکست در پشتیبانگیری» و اعلان پاسخ در انجمنهاست. این ایمیلها کوتاه و کمحجم هستند و یکییکی ارسال میشوند. یک relay این کار را انجام میدهد و راهاندازی آن تنها یک بعدازظهر زمان میبرد.
تصمیم بگیرید که واقعاً به دنبال حل کدامیک از این دو مسئله هستید. اینکه آیا راهاندازی mailbox شخصی هنوز ارزشش را دارد یا خیر یک پرسش واقعی با پاسخی واقعی است و برای اکثر افراد، پاسخ منفی است. اگر پاسخ شما مثبت است، استفاده از یک Mailcow mail server کامل روی یک VPS مسیر صادقانهای است. نیمهٔ دیگر، یعنی ارسال ایمیل، چیزی است که تقریباً همه به آن نیاز دارند اما تقریباً هیچکس برای آن برنامهریزی نمیکند.
ابتدا دو اصطلاح را تعریف میکنیم. SMTP (پروتکل ساده انتقال نامه) پروتکلی است که تمام بخشهای این فرآیند از آن استفاده میکنند. یک relay که به آن smarthost نیز میگویند، سروری است که ایمیلهای احراز هویتشدهٔ شما را میپذیرد و آنها را با استفاده از آدرسها و اعتبار خود به مقصد نهایی تحویل میدهد.
چرا VPS شما نمیتواند ایمیل را روی پورت 25 ارسال کند
تقریباً تمام ارائهدهندگان VPS بهصورت پیشفرض پورت خروجی TCP 25 را مسدود میکنند. پورت 25 پورتی است که سرورهای ایمیل برای ارتباط با یکدیگر از آن استفاده میکنند؛ بنابراین اگر یک VPS آلوده دسترسی خروجی به پورت 25 داشته باشد، میتواند مستقیماً برای هر سرور ایمیل گیرندهای اسپم ارسال کند. ارائهدهندگان بهجای رد کردن (refuse) این بستهها، آنها را حذف (drop) میکنند؛ به همین دلیل نشانهٔ این مسدودسازی، اتصالی است که معلق میماند و در نهایت با خطای timeout مواجه میشود، نه یک خطای مستقیم.
این موضوع را از روی سرور تست کنید:
sudo apt update && sudo apt install -y netcat-openbsd
nc -vz -w 5 gmail-smtp-in.l.google.com 25
nc -vz -w 5 smtp.relay.example 587اگر دستور اول به مدت پنج ثانیه کامل معلق میماند در حالی که دستور دوم بلافاصله پاسخ میدهد، مسدود بودن پورت تأیید میشود. برخی ارائهدهندگان پس از بررسی حساب کاربری، این محدودیت را برمیدارند، اما اکثر آنها چنین کاری نمیکنند.
مسدود بودن پورت، دلیل اصلی استفاده از relay نیست. حتی اگر پورت 25 باز باشد، ایمیلی که مستقیماً از یک آدرس IP تازه در VPS ارسال میشود، به پوشهٔ اسپم میرود یا مستقیماً رد میشود؛ زیرا آن آدرس سابقهٔ ارسال ندارد و در محدودهای قرار دارد که گیرندگان آن را فضای میزبانی (hosting space) تلقی میکنند. راهنمای ارسالکنندگان گوگل مستلزم داشتن DNS معکوس و مستقیم معتبر برای IP ارسالکننده است و بسیاری از آدرسهای VPS دارای رکورد PTR عمومی هستند که امکان تغییر آن را ندارید. یک relay آدرسهایی را در اختیار شما میگذارد که از قبل دارای سابقه هستند.
پورتهای submission راه خروج هستند. پورت 587 از STARTTLS پشتیبانی میکند که در آن نشست با متن ساده (cleartext) آغاز شده و سپس ارتقا مییابد. پورت 465 از TLS ضمنی (transport layer security) استفاده میکند که در آن نشست از همان بایت اول رمزنگاری میشود. هر دو پورت برای کلاینتهای احراز هویتشده در نظر گرفته شدهاند، هر دو در شبکههای VPS باز هستند و relay شما حداقل از یکی از آنها پشتیبانی میکند.
انتخاب یک رله و یک زیردامنه برای ارسال
ارائهدهندگان خدمات ایمیل تراکنشی متعددی وجود دارند که همگی وظیفه مشابهی را انجام میدهند. آنها را بر اساس چهار معیار ارزیابی کنید:
- داشتن پورت ارسال 587 یا 465، همراه با SMTP AUTH.
- قابلیت امضای DKIM با دامنه و انتخابگر (selector) اختصاصی خودتان، نه فقط با دامنه آنها.
- دسترسی به دادههای مربوط به بازگشت ایمیل (bounce) و شکایات (complaint) از طریق داشبورد یا webhook.
- داشتن پلن قیمتی متناسب با حجم ارسال شما. تا اوت 2026، چندین ارائهدهنده همچنان امکان ارسال چند هزار ایمیل در ماه را بهصورت رایگان فراهم میکنند. از آنجا که این شرایط بهطور مداوم تغییر میکنند، بهجای تکیه بر پستهای وبلاگی، صفحه قیمتگذاری فعلی آنها را مطالعه کنید.
ایمیلهای اپلیکیشن را از یک زیردامنه ارسال کنید. از چیزی مانند notify.example.com بهجای example.com استفاده کنید. گیرندگان، اعتبار را بر اساس دامنه ارزیابی میکنند؛ بنابراین یک ارسال نامناسب از اپلیکیشنهای شما، دامنهای که فاکتورها و ایمیلهای تیمتان از آن ارسال میشود را تحت تأثیر قرار نمیدهد. در مورد محدودیتها واقعبین باشید: برخی از گیرندگان، سیگنالهای زیردامنه را به دامنه اصلی (سازمانی) منتقل میکنند؛ بنابراین استفاده از زیردامنه، آسیب را کاهش میدهد اما لزوماً آن را بهطور کامل ایزوله نمیکند.
پیکربندی رله برای هر برنامه self-hosted تنها برای یکبار
رویکرد وسوسهانگیز این است که صفحه تنظیمات هر برنامه را باز کنید و میزبان SMTP، نام کاربری و رمز عبور را در آن وارد کنید. Nextcloud، انجمن، Grafana، Vaultwarden و مانیتور آپتایم همگی چنین فرمی دارند. اگر این کار را انجام دهید، اعتبارنامه در 6 مکان و با 6 فرمت مختلف ذخیره میشود که برخی از آنها درون پایگاه دادهای هستند که بهجای فایل پیکربندی، بهعنوان داده از آن نسخه پشتیبان میگیرید. وقتی رمز عبور را تغییر میدهید، باید 5 مورد از آنها را بهروزرسانی کنید. مورد ششم از کار میافتد و این اتفاق بیسروصدا رخ میدهد، زیرا اکثر برنامهها خطای SMTP را در سمت سرور ثبت میکنند و همچنان صفحه موفقیت را به کاربر نشان میدهند.
بهجای آن، آن را یکبار روی میزبان پیکربندی کنید و اجازه دهید برنامهها بهصورت محلی ارسال کنند. دو ابزار این کار را بهخوبی انجام میدهند و انتخاب بین آنها به موضوع صفبندی (queuing) مربوط است.
msmtp یک کلاینت سازگار با sendmail است که daemon ندارد. این ابزار متصل میشود، ارسال میکند و خارج میشود. این ابزار صف ندارد، بنابراین اگر رله در دسترس نباشد، پیام از دست میرود و برنامه فراخوان وضعیت خروج غیرصفر دریافت میکند.
Postfix که بهعنوان satellite پیکربندی شده باشد، یک عامل انتقال ایمیل کامل با صف واقعی است. این ابزار پیام را بلافاصله میپذیرد، در صورت شکست تا چند روز تلاش مجدد میکند و اعتبارنامه رله را در فایلی که فقط برای root قابل دسترسی است نگه میدارد. زمانی از آن استفاده کنید که از دست دادن یک هشدار در حین قطعی رله اهمیت دارد، یا زمانی که چندین برنامه با کاربران سیستمی متفاوت اجرا میشوند.
msmtp، گزینه سبک
sudo apt update
sudo apt install -y msmtp msmtp-mta ca-certificatesmsmtp-mta لینک نمادین /usr/sbin/sendmail را نصب میکند، بنابراین هر چیزی که sendmail را فراخوانی کند، بدون اینکه بداند msmtp وجود دارد، به آن میرسد.
فایل /etc/msmtprc را بنویسید:
defaults
auth on
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
syslog on
account relay
host smtp.relay.example
port 587
from apps@notify.example.com
set_from_header on
user <relay username>
password <relay password>
account default : relayset_from_header on همیشه یک هدر From تنظیم میکند و هر هدر موجود را بازنویسی میکند، بنابراین هر آنچه برنامه تولید کرده باشد را با آدرس موجود در from جایگزین میکند. بدون آن، یک cron job با نام root@your-hostname ارسال میکند و رله آن را رد میکند زیرا این آدرسی نیست که شما تأیید کرده باشید. syslog on لاگ را از طریق syslog ارسال میکند، بنابراین میتوانید آن را با journalctl -t msmtp بخوانید. یک مسیر مشترک logfile جایگزین است و به مجوز نوشتن برای هر کاربری که ایمیل ارسال میکند نیاز دارد، که در یک سیستم چندکاربره یک تله محسوب میشود.
مجوزها را خودتان تنظیم کنید. msmtp مجوزها را در پیکربندی هر کاربر (~/.msmtprc) اعمال میکند، جایی که با contains secrets and therefore must have no more than user read/write permissions از اجرا خودداری میکند. این ابزار هیچ محدودیتی روی /etc/msmtprc اعمال نمیکند، زیرا اگر فایل قابل خواندن باشد، بهسادگی آن را بارگذاری میکند.
sudo chown root:root /etc/msmtprc
sudo chmod 600 /etc/msmtprc
printf 'Subject: relay test\n\nsent from the host\n' | sudo sendmail -v you@example.com-v کل مکالمه SMTP را چاپ میکند، بنابراین هر پاسخ از رله را میبینید. یک ارسال موفق با پاسخ 250 که پیام را میپذیرد، پایان مییابد. یک خط authentication failed به این معنی است که نام کاربری یا رمز عبور اشتباه است، یا رله بهجای رمز عبور حساب، انتظار یک API key را دارد.
حالا نکته اصلی که دلیل روی آوردن بسیاری از افراد به Postfix است: با حالت 600 و مالکیت root، فقط root میتواند ارسال کند. برنامهای که بهعنوان www-data اجرا میشود نمیتواند فایل را بخواند، msmtp از آن صرفنظر میکند و برنامه با خطای پیدا نشدن حساب پیشفرض شکست میخورد. راهحل استفاده از یک گروه است:
sudo chgrp mail /etc/msmtprc
sudo chmod 640 /etc/msmtprc
sudo usermod -aG mail www-dataبهصراحت بگویید این یعنی چه: هر عضو گروه mail میتواند رمز عبور رله را بخواند و از آن سیستم با دامنه شما ایمیل ارسال کند. در یک VPS که بهتنهایی مدیریت میکنید، این قابلقبول است. در جایی که چندین برنامه که شما ننوشتهاید با کاربران مختلف اجرا میشوند، اینطور نیست و Postfix پاسخ بهتری است زیرا آن برنامهها هرگز اعتبارنامه را نمیبینند.
Postfix بهعنوان satellite
sudo debconf-set-selections <<'EOF'
postfix postfix/main_mailer_type select Satellite system
postfix postfix/mailname string notify.example.com
postfix postfix/relayhost string [smtp.relay.example]:587
EOF
sudo DEBIAN_FRONTEND=noninteractive apt install -y postfix libsasl2-moduleslibsasl2-modules اختیاری نیست. بدون آن Postfix خطای warning: SASL authentication failure: No worthy mechs found را ثبت میکند، زیرا کتابخانههای مکانیزم PLAIN و LOGIN تحت /usr/lib/sasl2 نصب نشدهاند.
بقیه را با postconf -e تنظیم کنید که /etc/postfix/main.cf را در محل ویرایش میکند:
sudo postconf -e 'relayhost = [smtp.relay.example]:587'
sudo postconf -e 'smtp_sasl_auth_enable = yes'
sudo postconf -e 'smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd'
sudo postconf -e 'smtp_sasl_security_options = noanonymous'
sudo postconf -e 'smtp_tls_security_level = encrypt'
sudo postconf -e 'smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt'
sudo postconf -e 'inet_interfaces = loopback-only'کروشههای اطراف نام میزبان رله، Postfix را از جستجوی رکورد MX برای آن نام باز میدارد و باعث میشود مستقیماً به آن نام متصل شود. برخی از نامهای میزبان رله رکوردهای MX منتشر میکنند که به جای دیگری اشاره دارند و بدون کروشه، ایمیل شما آنها را به سرور اشتباه دنبال میکند.
smtp_tls_security_level = encrypt استفاده از TLS را اجباری میکند، بنابراین پیام هرگز به صورت متن ساده ارسال نمیشود. این گزینه گواهی را تأیید نمیکند. مستندات خود Postfix در این مورد صریح است: در آن سطح، تحویل ادامه مییابد حتی اگر گواهی سرور غیرقابل اعتماد باشد یا نام اشتباهی داشته باشد. اگر میخواهید گواهی بررسی شود، از verify یا secure استفاده کنید و smtp_tls_CAfile را تنظیم نگه دارید.
اعتبارنامه در یک فایل که فقط برای root قابل دسترسی است قرار میگیرد:
echo '[smtp.relay.example]:587 relay-username:relay-password' | sudo tee /etc/postfix/sasl_passwd
sudo chmod 600 /etc/postfix/sasl_passwd
sudo postmap hash:/etc/postfix/sasl_passwd
sudo systemctl restart postfixpostmap نسخه ایندکسشدهای را میسازد که Postfix در واقع آن را میخواند. اگر فایل متنی را بعداً ویرایش کنید و postmap را فراموش کنید، Postfix به استفاده از پایگاه داده قدیمی ادامه میدهد و هیچ چیزی در لاگ به شما اطلاع نمیدهد. در Postfix 3.9 و جدیدتر، نوع نقشه پیشفرض lmdb است، بنابراین اگر ترجیح میدهید، lmdb: را هم در پارامتر و هم در آرگومان postmap بنویسید. نامگذاری نوع در هر دو خط چیزی است که آنها را هماهنگ نگه میدارد.
برنامهها همچنان ایمیل خود را با آدرس root@hostname ارسال میکنند. فرستنده را بازنویسی کنید:
echo '/.+/ apps@notify.example.com' | sudo tee /etc/postfix/sender_canonical
sudo postconf -e 'sender_canonical_classes = envelope_sender, header_sender'
sudo postconf -e 'sender_canonical_maps = regexp:/etc/postfix/sender_canonical'
sudo systemctl reload postfixیک جدول regexp: مستقیماً خوانده میشود، بنابراین نیازی به postmap ندارد. هر پیام اکنون با همان فرستنده پاکت (envelope sender) و همان هدر From خارج میشود که رله آن را میخواهد. هزینه این کار این است که پاسخها همگی در یک مکان فرود میآیند، بنابراین در هر برنامه یک هدر Reply-To تنظیم کنید تا پاسخها به دست شخص مربوطه برسد.
یک تست ارسال کنید و لاگ را بخوانید:
printf 'Subject: postfix relay test\n\nsent through the queue\n' | sendmail you@example.com
sudo tail -n 20 /var/log/mail.logیک پیام تحویلدادهشده، status=sent را به همراه پاسخ خود رله در کروشه ثبت میکند. هر چیز دیگری دلیل آن را بیان میکند. status=deferred با Connection timed out به این معنی است که چیزی هنوز به پورت 25 اشاره دارد. Host or domain name not found. Name service error for name=smtp.relay.example type=A به این معنی است که نام میزبان رله اشتباه است یا DNS روی سیستم خراب است. mailq موارد گیرکرده را لیست میکند و sudo postqueue -f اکنون آنها را دوباره تلاش میکند.
دسترسی به relay میزبان از داخل کانتینرهای Docker
یک کانتینر نمیتواند sendmail میزبان را فراخوانی کند، زیرا این باینری در image وجود ندارد و صف (queue) نیز به اشتراک گذاشته نشده است. به جای آن، یک مقصد شبکه برای کانتینرها تعریف کنید. Postfix میتواند روی آدرس bridge شبکه Docker گوش دهد.
ip -4 addr show docker0
sudo postconf -e 'inet_interfaces = 127.0.0.1, 172.17.0.1'
sudo postconf -e 'mynetworks = 127.0.0.0/8 172.17.0.0/16'
sudo systemctl restart postfixآدرس bridge خود را از دستور اول بخوانید و از کپی کردن این دستور خودداری کنید، زیرا هر پروژه Compose شبکه اختصاصی خود را در یک subnet متفاوت ایجاد میکند و docker network inspect <name> آن را نمایش میدهد. در اینجا از restart استفاده کنید و نه reload؛ مستندات Postfix تأکید دارند که پس از تغییر inet_interfaces باید سرویس را متوقف و دوباره راهاندازی کنید، چرا که reload تغییرات را اعمال نمیکند. هر برنامه سپس از SMTP host با آدرس 172.17.0.1 و پورت 25 استفاده میکند، بدون احراز هویت و بدون TLS، زیرا این ترافیک هرگز از میزبان خارج نمیشود. اگر سرویسهای شما روی یک شبکه Compose قرار دارند، اجرای Docker Compose روی یک VPS توضیح میدهد که این subnet از کجا میآید.
این مرحلهای است که میتواند برای شما مشکلساز شود. اگر Postfix روی یک آدرس عمومی با mynetworks باز گوش دهد، به یک open relay تبدیل میشود: افراد ناشناس ایمیلهای خود را از طریق relay شما ارسال میکنند، ارائهدهنده سرویس، حساب شما را مسدود میکند و اعتبار دامنه شما برای ماهها آسیب میبیند. پس از هر تغییر، هر دو سمت را بررسی کنید.
ss -tlnp | grep ':25'خروجی باید فقط آدرس loopback و آدرس bridge را نشان دهد. از یک ماشین دیگر، nc -vz your.server.ip 25 باید با شکست مواجه شود.
تنظیم SPF، DKIM و DMARC برای دامنه ارسالکننده
پیش از اولین ارسال واقعی، هر سه رکورد را منتشر کنید. این رکوردها رایگان هستند، در DNS قرار میگیرند و اولین مواردی هستند که گیرندگان بررسی میکنند.
SPF (چارچوب سیاست فرستنده) مشخص میکند چه کسی اجازه دارد نام دامنه شما را در envelope sender قرار دهد. آن را روی زیردامنه ارسالکننده منتشر کنید:
notify.example.com. IN TXT "v=spf1 include:_spf.relay.example -all"مقدار include: را از صفحه تنظیمات relay خود کپی کنید، زیرا یک include که resolve نشود، بهجای وضعیت pass، یک خطای دائمی ایجاد میکند. ارزیابی SPF پس از 10 مکانیزم پرسوجوی DNS متوقف شده و permerror برمیگرداند که گیرندگان آن را به عنوان شکست (failure) تلقی میکنند، بنابراین تعداد includeها را محدود نگه دارید. دقیقاً یک رکورد v=spf1 برای هر نام منتشر کنید: وجود دو رکورد نیز یک permerror محسوب میشود.
DKIM (ایمیل شناساییشده با کلید دامنه) هر پیام را با یک کلید خصوصی که در اختیار relay است امضا میکند و گیرندگان کلید عمومی منطبق را از DNS دریافت میکنند. relay شما یک selector و یک رکورد TXT یا CNAME برای انتشار به شما میدهد:
sel1._domainkey.notify.example.com. IN CNAME sel1.dkim.relay.example.اهمیت DKIM از SPF بیشتر است، زیرا DKIM در فرآیند forward شدن پیام نیز باقی میماند. هنگامی که یک لیست پستی یا یک قانون .forward پیام شما را منتقل میکند، پیام از آدرس IP آن forwarder میرسد؛ بنابراین SPF شکست میخورد، اما امضا همچنان تأیید میشود.
DMARC (احراز هویت، گزارشدهی و انطباق پیام بر اساس دامنه) به گیرندگان میگوید در صورت عدم انطباق هر یک از بررسیها چه کاری انجام دهند و از آنها میخواهد گزارش بازگردانند. آن را روی دامنه سازمانی منتشر کنید:
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com; adkim=r; aspf=r"با p=none شروع کنید و گزارشها را به مدت 2 هفته مطالعه کنید. p=none هیچ تغییری در تحویل پیام ایجاد نمیکند و فقط گزارشدهی را فعال میکند؛ این همان روشی است که از طریق آن متوجه میشوید کدام سیستمها را فراموش کرده بودید که از طرف دامنه شما ایمیل ارسال میکنند. سپس به p=quarantine و در نهایت به p=reject بروید. انتشار p=reject در روز اول باعث میشود کاربران متوجه شوند سیستم صدور فاکتورشان از طرف دامنه ایمیل میفرستاده است، آن هم از طریق مشتریانی که هرگز فاکتوری دریافت نکردهاند.
بررسی کنید که دنیا چه چیزی را میبیند، نه آنچه پنل DNS شما نشان میدهد:
dig +short TXT notify.example.com
dig +short TXT sel1._domainkey.notify.example.com
dig +short TXT _dmarc.example.comخروجی خالی به این معنی است که رکورد هنوز منتشر (propagate) نشده یا نام آن اشتباه است. رکوردی که 5 دقیقه پیش اصلاح کردهاید ممکن است به دلیل TTL (زمان ماندگاری) قبلی همچنان در کشها به صورت اشتباه باقی بماند؛ بنابراین پیش از هر نتیجهگیری، TTL را بررسی کنید.
همراستا نگهداشتن From و Return-Path
هر پیام شامل دو آدرس فرستنده است که به شیوههای متفاوتی بررسی میشوند. فرستنده پاکت (envelope sender) در دستور SMTP MAIL FROM مشخص میشود و در پیام تحویلدادهشده به صورت Return-Path ظاهر میگردد. هدر From همان آدرسی است که خواننده مشاهده میکند.
پروتکل SPF دامنهٔ فرستندهٔ پاکت را با IP متصلشونده تطبیق میدهد. پروتکل DKIM دامنهای را گزارش میکند که پیام را امضا کرده است، که با d= مشخص میشود. پروتکل DMARC تنها زمانی تأیید میشود که حداقل یکی از این دو دامنه با دامنهٔ موجود در هدر From همراستا باشد. در حالت همراستایی منعطف (adkim=r، aspf=r که حالت پیشفرض است)، زیردامنه نیز پذیرفته میشود؛ بنابراین فرستندهٔ پاکت در notify.example.com با هدر From در example.com همراستا محسوب میشود. در حالت همراستایی سخت (strict alignment)، این تطبیق انجام نمیشود.
قانون عملی ساده است: هدر From و فرستندهٔ پاکت را روی یک دامنه قرار دهید تا این مسئله هرگز پیش نیاید. این دقیقاً همان کاری است که set_from_header on در msmtp و sender_canonical_maps در Postfix انجام میدهند.
نتیجهٔ بررسی را در پیام تحویلدادهشده بخوانید. در Gmail، گزینه "Show original" هدر نوشتهشده توسط گیرنده را نمایش میدهد:
Authentication-Results: mx.google.com;
dkim=pass header.i=@notify.example.com;
spf=pass (google.com: domain of apps@notify.example.com designates 198.51.100.25 as permitted sender) smtp.mailfrom=apps@notify.example.com;
dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=example.comدر اینجا هر سه بررسی با موفقیت انجام شدهاند. هر نتیجهٔ دیگری، نام بررسی ناموفق و معمولاً دلیل آن را ذکر میکند که سریعترین اطلاعات برای عیبیابی در این زمینه است.
بازگشتها و شکایات، پیش از رسیدن حجم ایمیلها
بازگشت (Bounce) زمانی رخ میدهد که گیرنده پیام شما را رد کند. یک بازگشت سخت (Hard bounce) دائمی است و Gmail آن را با عبارت 550 5.1.1 The email account that you tried to reach does not exist توصیف میکند. بازگشت نرم (Soft bounce) موقتی است و یک کد 4xx برای پر بودن صندوق ورودی یا greylisting محسوب میشود که در این حالت، رله (relay) بهطور خودکار دوباره تلاش میکند.
رلهها نرخ بازگشت سخت شما را اندازهگیری میکنند و حسابهایی را که به ارسال ایمیل به آدرسهای ناموجود ادامه میدهند، مسدود میکنند؛ زیرا این الگو مشابه رفتار لیستهای خریداریشده است. شکایات اهمیت بیشتری دارند. شکایت زمانی است که یک شخص دکمه اسپم را فشار میدهد. راهنمای فرستندگان گوگل (بررسیشده در اوت 2026) از فرستندگان میخواهد نرخ اسپم گزارششده در Postmaster Tools را زیر 0.30% نگه دارند و توصیه میکند که این نرخ زیر 0.10% باشد.
چهار موردی که باید پیش از رسیدن حجم ایمیلها آماده باشند:
- یک webhook، یا بررسی هفتگی لیست suppression رله، تا بتوانید بازگشتها را مشاهده کنید.
- یک آدرس From که یک صندوق ورودی واقعی است و کسی آن را میخواند، با تنظیم
Reply-Toدر جایی که پاسخها باید ارسال شوند. - تأیید پیش از اضافه شدن هر آدرس به لیست، تا هرگز به آدرسی که صاحبش آن را وارد نکرده است، ایمیل نفرستید.
- محدودیت نرخ (rate limit) روی هر فرمی که ایمیل ارسال میکند.
دو مورد آخر همانجایی است که برنامههای self-hosted ابتدا در آن شکست میخورند. یک فرم ثبتنام محافظتنشده به هر کسی اجازه میدهد آدرس یک غریبه را وارد کند، سرور شما تأییدیه را میفرستد و آن غریبه ایمیل را به عنوان اسپم علامتگذاری میکند. متوقف کردن بمباران اشتراک در فرم ثبتنام هم یک وظیفه مربوط به تحویل ایمیل (deliverability) است و هم یک وظیفه مربوط به مقابله با سوءاستفاده.
ایمیلهای انبوه (bulk mail) را از این مسیر دور نگه دارید. خبرنامهها به مدیریت لیست و هدرهای لغو اشتراک (unsubscribe headers) نیاز دارند که ایمیلهای تراکنشی (transactional) فاقد آنها هستند؛ بنابراین آنها را از طریق یک نمونه Listmonk به صورت self-hosted روی زیردامنه اختصاصی خود با اعتبار (reputation) مجزا اجرا کنید. ایمیلهای اطلاعرسانی از یک انجمن به صورت self-hosted در میان این دو قرار میگیرند؛ از نظر ساختار تراکنشی هستند و از نظر حجم انبوه، و معمولاً اولین چیزی هستند که به شما نشان میدهند آیا تنظیمات شما پایدار است یا خیر.
برای اطلاع، قوانین فرستندگان انبوه Gmail برای بیش از 5,000 پیام در روز به آدرسهای Gmail اعمال میشود و نیازمند SPF، DKIM، DMARC و لغو اشتراک تککلیکی در ایمیلهای بازاریابی است. اکثر برنامههای self-hosted هرگز به این حد نمیرسند. با این حال، بخش احراز هویت (authentication) اکنون از هر فرستندهای فارغ از حجم ارسال، انتظار میرود.
پیش از اعتماد، آن را تست کنید
swaks ابزار مناسب برای این کار است. این ابزار از پروتکل SMTP استفاده میکند و کل مکالمه را نمایش میدهد تا متوجه شوید کدام مرحله با شکست مواجه شده است.
sudo apt install -y swaks
swaks --to you@example.com --from apps@notify.example.com --server smtp.relay.example --port 587 --tls --auth-user '<relay username>' --auth-password '<relay password>'این دستور اعتبارنامهها را مستقیماً روی relay تست میکند. برای تست مسیری که برنامههای شما واقعاً از آن استفاده میکنند، آن را به سمت host relay نشانه بروید:
swaks --to you@example.com --from apps@notify.example.com --server 127.0.0.1سپس نتیجه را به صورت سرتاسری (end-to-end) از روی سرور و با ایمیل واقعی بررسی کنید. هیچکدام از این موارد با فایلهای پیکربندی قابل اثبات نیستند، پس خودتان آن را اجرا کنید:
- ارسال به یک سرویس امتیازدهی مانند mail-tester.com که SPF، DKIM، DMARC و محتوای پیام شما را میخواند و دلایل امتیاز دریافتی را اعلام میکند.
- ارسال به یک صندوق پستی در هر یک از دو ارائهدهندهای که کاربران شما واقعاً از آنها استفاده میکنند و خواندن
Authentication-Resultsدر پیام خام (raw message). - بررسی یک پیام از طریق learndmarc.com در صورتی که نتیجه همترازی (alignment) واضح نیست.
- فعالسازی ارسال از خودِ برنامه، نه فقط از خط فرمان، زیرا این برنامه است که هدر From را تنظیم میکند.
یک هشدار صادقانه برای پایان: یک دامنه کاملاً جدید با هر سه رکورد صحیح، گاهی همچنان به پوشه اسپم میرود؛ زیرا هیچ سابقهای ندارد و دریافتکنندگان نسبت به دامنههایی که همین هفته ایجاد شدهاند، محتاط هستند. کار را کوچک شروع کنید و ایمیلهایی بفرستید که مردم انتظار دریافت آنها را دارند. اعتبار از همانجا ساخته میشود و هیچ پیکربندیای نمیتواند این مرحله را دور بزند.
FAQ
چرا پورت خروجی 25 روی VPS من مسدود است؟
تقریباً تمام ارائهدهندگان، پورت خروجی TCP 25 را بهصورت پیشفرض مسدود میکنند؛ زیرا یک سرور آلوده با پورت باز میتواند مستقیماً اسپم به سرورهای ایمیل مقصد ارسال کند. بستهها به جای رد شدن (refuse)، دور ریخته میشوند (drop)؛ بنابراین نشانهٔ این وضعیت، اتصالی است که معلق میماند و در نهایت با timeout مواجه میشود، نه یک پیام خطا. این موضوع را با اجرای nc -vz -w 5 gmail-smtp-in.l.google.com 25 در کنار nc -vz -w 5 smtp.relay.example 587 تأیید کنید: اولی معلق میماند، اما دومی بلافاصله پاسخ میدهد. راهکار، درخواست برای رفع مسدودیت نیست. از طریق یک relay روی پورت submission یعنی 587 یا 465 ایمیل بفرستید که باز هستند و برای کلاینتهای احراز هویتشده در نظر گرفته شدهاند.
آیا برای ارسال چند اعلان اپلیکیشن، واقعاً به SPF، DKIM و DMARC نیاز دارم؟
بله، و حجم ارسال تأثیری در این موضوع ندارد. گیرندگان همان بررسیها را برای یک ایمیل بازنشانی رمز عبور اعمال میکنند که برای یک کمپین پنجاه هزارتایی انجام میدهند. بدون SPF و DKIM، ایمیل شما احراز هویتنشده است و راهنمای فعلی گوگل برای فرستندگان، حداقل یکی از این دو را برای هر فرستندهای الزامی میداند. بدون DMARC هیچ گزارشی دریافت نمیکنید، بنابراین اولین نشانهٔ بروز مشکل، کاربری خواهد بود که میگوید لینک بازنشانی هرگز به دستش نرسیده است. هر سه مورد، رکوردهای DNS هستند، هزینهای ندارند و انتشار آنها حدود 10 دقیقه زمان میبرد.
آیا باید از msmtp یا Postfix به عنوان کلاینت relay استفاده کنم؟
زمانی که یک نفر مدیریت سرور را بر عهده دارد و از دست دادن یک پیام در زمان قطعی relay قابلقبول است، از msmtp استفاده کنید. این ابزار یک فایل پیکربندی واحد بدون daemon است و چون صف (queue) ندارد، در صورت در دسترس نبودن relay، پیام از بین میرود. زمانی که به صفی نیاز دارید که برای چند روز تلاش مجدد انجام دهد، یا وقتی چندین اپلیکیشن با کاربران سیستمی متفاوت اجرا میشوند، از Postfix به عنوان satellite استفاده کنید. Postfix رمز عبور relay را در فایلی نگه میدارد که فقط برای root قابلخواندن است، در حالی که msmtp نیاز دارد پیکربندیاش توسط هر کاربری که ایمیل میفرستد، قابلخواندن باشد.
چرا ایمیل اپلیکیشن من به دلیل ارسال از root رد میشود؟
کرونجابها و بسیاری از اپلیکیشنها، آدرس فرستنده را از نام کاربری محلی و hostname میسازند و چیزی شبیه به root@srv1.localdomain تولید میکنند. این آدرسی نیست که شما در relay تأیید کرده باشید، بنابراین relay پیام را با یک پاسخ 553 یا 554 که نام آدرس فرستنده در آن ذکر شده، رد میکند. این مشکل را در سطح host حل کنید نه در تکتک اپلیکیشنها: set_from_header on به همراه یک آدرس from در /etc/msmtprc، یا sender_canonical_maps با sender_canonical_classes = envelope_sender, header_sender در Postfix. اگر پاسخها باید به دست یک شخص برسد، Reply-To را در داخل هر اپلیکیشن تنظیم کنید.
آیا استفاده از یک زیردامنه (subdomain) جداگانه برای ایمیلهای اپلیکیشن، واقعاً از دامنه اصلی من محافظت میکند؟
تا حدی، و همچنان ارزش انجام دادن دارد. گیرندگان اعتبار را بر اساس دامنه ردیابی میکنند، بنابراین شکایات علیه notify.example.com عمدتاً در محدوده notify.example.com باقی میماند و دامنه اصلی شما به ارسال ایمیل ادامه میدهد. محدودیت واقعی این است: برخی گیرندگان سیگنالهای زیردامنه را به دامنه سازمانی (organisational domain) منتقل میکنند و سیاست DMARC منتشرشده در سطح سازمانی، برای زیردامنهها نیز اعمال میشود مگر اینکه sp= را جداگانه تنظیم کنید. به زیردامنه به عنوان ابزاری برای محدود کردن خسارت نگاه کنید، نه یک تضمین قطعی.