Self-hosted অ্যাপ থেকে mail পাঠানোর সহজ SMTP সেটআপ
Self-hosted অ্যাপ থেকে mail server ছাড়াই পাঠান: host-level authenticated SMTP relay, SPF, DKIM ও DMARC সেটআপ এবং blocked port 25 ঠিক করার বাস্তব নির্দেশনা।
কোন self-hosted অ্যাপের mail পাঠানো দরকার
self-hosted অ্যাপ থেকে mail পাঠাতে আপনার mail server দরকার নেই। আপনার দরকার একটি relay: host-এ একবার configure করা একটি authenticated SMTP account, যেখানে ওই server-এর প্রতিটি অ্যাপ outgoing mail পাঠাবে। Mailbox চালানোই কঠিন কাজ, এবং এটি আলাদা একটি সমস্যা।
Mail গ্রহণের অর্থ হলো পুরো Internet থেকে port 25-এ connection গ্রহণ করা, spam filter করা, mailbox সংরক্ষণ ও backup করা, এবং server থাকা পর্যন্ত IP reputation বজায় রাখা। এই কাজটি বাস্তবে আগের চেয়ে কঠিন হয়েছে। Mail পাঠানোর মধ্যে password reset, signup confirmation, "backup failed" alert এবং forum reply notification পড়ে। এগুলো ছোট আকারের, কম volume-এর এবং একবারে একটি করে পাঠানো হয়। একটি relay এগুলো পরিচালনা করে, এবং এটি সেট up করতে সাধারণত একটি বিকেলই লাগে।
আপনি আসলে কোন দুটি সমস্যার সমাধান করতে চাইছেন, তা নির্ধারণ করুন। নিজের mailbox চালানো এখনও উপযোগী কি না—এটি বাস্তব প্রশ্ন, এবং এর বাস্তব উত্তর আছে। অধিকাংশ মানুষের ক্ষেত্রে উত্তর হলো না। আপনার উত্তর যদি হ্যাঁ হয়, VPS-এ একটি পূর্ণ Mailcow mail server হলো সৎ ও সরাসরি পথ। অন্য অর্ধেকটি হলো mail পাঠানো, যা প্রায় সবারই দরকার, কিন্তু প্রায় কেউই আগে থেকে এর পরিকল্পনা করে না।
প্রথমে দুটি term জেনে নিন। SMTP (simple mail transfer protocol) হলো এই ব্যবস্থার প্রতিটি অংশে ব্যবহৃত protocol। Relay-কে smarthost-ও বলা হয়। এটি এমন একটি server, যা আপনার authenticated mail গ্রহণ করে এবং নিজের address ও নিজের reputation ব্যবহার করে সেটি পরবর্তী গন্তব্যে deliver করে।
VPS কেন port 25-এ mail পাঠাতে পারে না
প্রায় সব VPS provider ডিফল্টভাবে outbound TCP port 25 block করে। Mail server-গুলো পরস্পরের সঙ্গে যোগাযোগ করতে port 25 ব্যবহার করে। তাই outbound port 25 খোলা থাকা কোনো breached VPS প্রতিটি receiving mail server-এ সরাসরি spam পাঠাতে পারে। Provider-গুলো এই packet প্রত্যাখ্যান না করে drop করে। তাই connection error দেখানোর বদলে ঝুলে থাকে এবং পরে timeout হয়।
Server থেকে পরীক্ষা করুন:
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প্রথম command-টি যদি পুরো পাঁচ সেকেন্ড অপেক্ষা করে, আর দ্বিতীয়টি সঙ্গে সঙ্গে উত্তর দেয়, তাহলে block নিশ্চিত। কিছু provider account review-এর পরে এটি খুলে দেয়। অধিকাংশ provider তা করে না।
Relay ব্যবহার করার প্রধান কারণ এই block নয়। port 25 খোলা থাকলেও নতুন VPS address থেকে সরাসরি পাঠানো mail spam folder-এ যায় অথবা সরাসরি প্রত্যাখ্যাত হয়। কারণ ওই address-এর কোনো sending history নেই এবং এটি এমন একটি range-এ রয়েছে, যেটিকে receiving server-গুলো hosting space হিসেবে বিবেচনা করে। Google-এর sender guidance অনুযায়ী sending IP-এর valid forward এবং reverse DNS থাকতে হয়। অনেক VPS address-এ generic PTR (pointer) record থাকে, যা আপনি পরিবর্তন করতে পারেন না। Relay এমন address দেয়, যেগুলোর আগে থেকেই sending history আছে।
Submission port ব্যবহার করলেই এই সমস্যা এড়ানো যায়। Port 587 STARTTLS বহন করে। এতে session cleartext অবস্থায় শুরু হয় এবং পরে encrypted হয়। Port 465 implicit TLS (transport layer security) বহন করে। এতে প্রথম byte থেকেই session encrypted থাকে। উভয় port-ই authenticated client-এর জন্য নির্ধারিত, VPS network-এ উভয়ই খোলা থাকে, এবং আপনার relay অন্তত একটি port সমর্থন করে।
একটি relay এবং একটি sending subdomain বেছে নিন
অনেক transactional mail provider আছে, এবং তারা একই কাজ করে। চারটি বিষয় দেখে তাদের মূল্যায়ন করুন:
- SMTP AUTH-সহ 587 বা 465 নম্বর submission port
- আপনার নিজস্ব domain এবং selector দিয়ে DKIM signing; শুধু provider-এর domain ও selector দিয়ে নয়
- dashboard বা webhook-এর মাধ্যমে পড়া যায় এমন bounce এবং complaint data
- আপনার mail volume-এর উপযোগী একটি tier। August 2026 পর্যন্ত কয়েকটি provider এখনও প্রতি মাসে বিনা খরচে কয়েক হাজার message পাঠানোর সুবিধা দেয়। এই শর্তগুলো প্রায়ই বদলে যায়। তাই কোনো blog post-এর বদলে বর্তমান pricing page পড়ুন
একটি subdomain থেকে app mail পাঠান। example.com-এর বদলে notify.example.com-এর মতো কিছু ব্যবহার করুন। Receiver-রা প্রতিটি domain-এর reputation আলাদাভাবে মূল্যায়ন করে। তাই আপনার app থেকে পাঠানো খারাপ mail যেন invoices এবং আপনার team-এর mail ব্যবহৃত domain-এর reputation নষ্ট না করে। সীমাবদ্ধতাটি স্পষ্টভাবে মনে রাখুন: কিছু receiver subdomain-এর signal organisational domain-এও প্রয়োগ করে। তাই subdomain ক্ষতি কমায়, কিন্তু সম্পূর্ণ আলাদা করে না।
প্রতিটি self-hosted অ্যাপের জন্য relay একবার কনফিগার করুন
প্রতিটি অ্যাপের settings page খুলে SMTP host, username এবং password বসিয়ে দেওয়াই সহজ মনে হয়। Nextcloud, forum, Grafana, Vaultwarden এবং uptime monitor—সবকটিতেই এই form থাকে। এভাবে করলে credential ছয়টি জায়গায়, ছয়টি format-এ থেকে যায়। এর কয়েকটি এমন database-এর ভেতরে থাকে, যেটিকে আপনি config নয়, data হিসেবে backup করেন। Password পরিবর্তন করলে পাঁচটি জায়গা আপডেট করবেন। ষষ্ঠটি mail পাঠানো বন্ধ করবে। অধিকাংশ অ্যাপ server side-এ SMTP error log করে, কিন্তু ব্যবহারকারীকে success page দেখায়। তাই এটি নীরবে ঘটবে।
এর বদলে host-এ একবার কনফিগার করুন এবং অ্যাপগুলোকে locally submit করতে দিন। এই কাজের জন্য দুটি tool ভালো। তাদের মধ্যে নির্বাচন মূলত queuing-এর প্রয়োজনের ওপর নির্ভর করে।
msmtp হলো daemon ছাড়া sendmail-compatible client। এটি connect করে, mail পাঠায় এবং exit করে। এটি queue করে না। তাই relay-এ পৌঁছানো না গেলে message হারিয়ে যায় এবং calling app non-zero exit status পায়।
Satellite হিসেবে কনফিগার করা Postfix হলো real queue-সহ একটি পূর্ণ mail transfer agent। এটি সঙ্গে সঙ্গে message গ্রহণ করে, failure হলে কয়েক দিন retry করে এবং root-only file-এ relay credential রাখে। Relay outage-এর সময় কোনো alert হারানো গুরুত্বপূর্ণ হলে, অথবা একাধিক app ভিন্ন system user হিসেবে চললে এটি ব্যবহার করুন।
ছোট বিকল্প: msmtp
sudo apt update
sudo apt install -y msmtp msmtp-mta ca-certificatesmsmtp-mta, /usr/sbin/sendmail symlink ইনস্টল করে। তাই sendmail কল করে এমন যেকোনো কিছু msmtp-তে পৌঁছে যায়, যদিও সেটি 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 header সেট করে এবং আগের header থাকলে তা প্রতিস্থাপন করে। ফলে app যে address তৈরি করেছিল, সেটির বদলে from-এর address ব্যবহৃত হয়। এটি না থাকলে cron job root@your-hostname হিসেবে mail পাঠায়। Relay সেটি প্রত্যাখ্যান করে, কারণ এটি আপনার verified address নয়। syslog on log-কে syslog-এর মাধ্যমে পাঠায়। তাই journalctl -t msmtp দিয়ে তা পড়ুন। বিকল্প হিসেবে shared logfile path ব্যবহার করা যায়। তবে mail পাঠানো প্রতিটি user-এর জন্য এতে write permission লাগবে। Multi-user box-এ এটি একটি security সমস্যা।
Permission নিজে সেট করুন। Per-user config (~/.msmtprc)-এর ক্ষেত্রে msmtp permission পরীক্ষা করে এবং contains secrets and therefore must have no more than user read/write permissions থাকলে চলতে অস্বীকার করে। /etc/msmtprc-এর ক্ষেত্রে এটি কোনো permission enforcement করে না। File readable হলে শুধু সেটি load করে।
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 conversation দেখায়। ফলে relay-এর প্রতিটি reply দেখতে পাবেন। সফল send শেষ হলে message গ্রহণ করার একটি 250 reply দেখা যায়। authentication failed line-এর অর্থ username বা password ভুল, অথবা relay account password-এর বদলে API key প্রত্যাশা করছে।
এখন সমস্যাটি হলো, এবং এ কারণেই অনেকে শেষ পর্যন্ত Postfix ব্যবহার করেন। Mode 600 এবং owner root হলে শুধু root mail পাঠাতে পারে। www-data হিসেবে চলা app file পড়তে পারে না। msmtp file-টি এড়িয়ে যায় এবং app default account না পাওয়ার error দেখিয়ে ব্যর্থ হয়। এর সমাধান হলো একটি group:
sudo chgrp mail /etc/msmtprc
sudo chmod 640 /etc/msmtprc
sudo usermod -aG mail www-dataএর অর্থ স্পষ্টভাবে বুঝে নিন: mail group-এর প্রতিটি member relay password পড়তে পারবে এবং সেই box থেকে আপনার domain হিসেবে mail পাঠাতে পারবে। আপনি একাই পরিচালনা করেন এমন VPS-এ এটি গ্রহণযোগ্য। আপনার লেখা নয় এমন একাধিক app ভিন্ন user হিসেবে চললে এটি গ্রহণযোগ্য নয়। সে ক্ষেত্রে Postfix ভালো উত্তর, কারণ ওই app-গুলো credential কখনো দেখতে পায় না।
Satellite হিসেবে Postfix
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 log করে, কারণ PLAIN এবং LOGIN mechanism-এর library /usr/lib/sasl2-এর অধীনে ইনস্টল করা নেই।
postconf -e দিয়ে বাকি সেটিংস নির্ধারণ করুন। এটি সরাসরি /etc/postfix/main.cf edit করে:
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'Relay hostname-এর চারপাশের square bracket Postfix-কে ওই নামের জন্য MX record lookup করা থেকে বিরত রাখে এবং সরাসরি সেই name-এ connect করায়। কিছু relay hostname অন্য কোথাও নির্দেশ করা MX record প্রকাশ করে। Bracket না থাকলে আপনার mail সেই record অনুসরণ করে ভুল server-এ চলে যেতে পারে।
smtp_tls_security_level = encrypt TLS বাধ্যতামূলক করে। ফলে message cleartext-এ পাঠানো হয় না। তবে এটি certificate verify করে না। Postfix-এর documentation এ বিষয়ে স্পষ্ট: ওই স্তরে server certificate untrusted হলেও বা ভুল name বহন করলেও delivery চলতে থাকে। Certificate যাচাই করতে চাইলে verify অথবা secure ব্যবহার করুন এবং smtp_tls_CAfile সেট রাখা নিশ্চিত করুন।
Credential একটি root-only file-এ রাখুন:
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 indexed copy তৈরি করে, যেটি Postfix বাস্তবে পড়ে। পরে text file edit করে postmap চালাতে ভুললে Postfix পুরোনো database ব্যবহার করতে থাকবে। Log-এ এ বিষয়ে কোনো বার্তা নাও থাকতে পারে। Postfix 3.9 এবং পরবর্তী version-এ default map type হলো lmdb। তাই এটি ব্যবহার করতে চাইলে parameter এবং postmap argument—দুই জায়গাতেই lmdb: লিখুন। দুই line-এ type উল্লেখ করলেই তারা একই configuration ব্যবহার করে।
App-গুলো এখনও তাদের mail root@hostname হিসেবে address করবে। Sender rewrite করুন:
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 postfixregexp: table সরাসরি পড়া হয়। তাই এর জন্য postmap লাগে না। এখন প্রতিটি message একই envelope sender এবং একই From header নিয়ে বের হবে। Relay-এর প্রয়োজন এটিই। এর ফলে সব reply একই জায়গায় পৌঁছাবে। তাই যেখানে কোনো ব্যক্তির কাছে reply পৌঁছানো উচিত, প্রতিটি app-এ একটি Reply-To header সেট করুন।
একটি test পাঠিয়ে log পড়ুন:
printf 'Subject: postfix relay test\n\nsent through the queue\n' | sendmail you@example.com
sudo tail -n 20 /var/log/mail.logDelivered message-এ status=sent এবং তার পরে bracket-এর মধ্যে relay-এর নিজস্ব reply log হয়। অন্য যেকোনো output কারণটি জানায়। status=deferred-এর সঙ্গে Connection timed out থাকলে কোনো configuration এখনও port 25-এ নির্দেশ করছে। Host or domain name not found. Name service error for name=smtp.relay.example type=A-এর অর্থ relay hostname ভুল, অথবা box-এ DNS কাজ করছে না। mailq আটকে থাকা message-এর তালিকা দেখায় এবং sudo postqueue -f সেগুলো এখনই retry করে।
Docker container থেকে host relay-এ সংযোগ করা
একটি container host-এর sendmail চালাতে পারে না, কারণ binary-টি image-এ নেই এবং queue-টিও shared নয়। তাই container-গুলোর জন্য একটি network target দিন। Postfix Docker bridge address-এ listen করতে পারে।
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প্রথম command-এর output থেকে নিজের bridge address দেখুন। এই address-টি এখানে দেওয়া address-এর পরিবর্তে ব্যবহার করুন, কারণ একটি Compose project আলাদা subnet-এ নিজস্ব network তৈরি করে এবং docker network inspect <name> সেটিই দেখায়। এখানে reload নয়, restart ব্যবহার করুন। Postfix-এর documentation অনুযায়ী inet_interfaces পরিবর্তন করার পরে service-টি stop করে আবার start করতে হবে। Reload করলে পরিবর্তন কার্যকর হবে না। এরপর প্রতিটি app-এর SMTP host হবে 172.17.0.1, port হবে 25, এবং authentication ও TLS থাকবে না। কারণ এই traffic host-এর বাইরে যায় না। আপনার service-গুলো যদি Compose network-এ থাকে, একটি VPS-এ Docker Compose চালানো-সংক্রান্ত নির্দেশনায় ওই subnet কোথা থেকে এসেছে তা ব্যাখ্যা করা হয়েছে।
এই ধাপে ভুল হলে গুরুতর সমস্যা হতে পারে। Public address-এ listen করা এবং বিস্তৃত mynetworks থাকা Postfix একটি open relay তৈরি করে। অপরিচিতরা আপনার relay account ব্যবহার করে mail পাঠাবে, provider account suspend করতে পারে এবং আপনার domain-এর reputation কয়েক মাসের জন্য ক্ষতিগ্রস্ত হবে। প্রতিটি পরিবর্তনের পরে উভয় দিক পরীক্ষা করুন।
ss -tlnp | grep ':25'Output-এ শুধু loopback address এবং bridge address দেখা যেতে হবে। অন্য machine থেকে nc -vz your.server.ip 25 ব্যর্থ হতে হবে।
sending domain-এর জন্য SPF, DKIM এবং DMARC
প্রথম বাস্তব বার্তা পাঠানোর আগে তিনটি record-ই publish করুন। এগুলো বিনামূল্যে, এগুলো DNS record, এবং receiver-রা প্রথমে এগুলোই পরীক্ষা করে।
SPF (sender policy framework) নির্ধারণ করে envelope sender-এ আপনার domain ব্যবহার করার অনুমতি কার আছে। এটি sending subdomain-এ publish করুন:
notify.example.com. IN TXT "v=spf1 include:_spf.relay.example -all"আপনার relay-এর নিজস্ব setup page থেকে include:-এর value কপি করুন। কারণ resolve না হওয়া include pass-এর বদলে permanent error তৈরি করে। SPF evaluation সর্বোচ্চ দশটি DNS-query করা mechanism-এর পরে থেমে permerror ফেরত দেয়। Receiver-রা এটিকে failure হিসেবে গণ্য করে। তাই include-এর সংখ্যা কম রাখুন। প্রতিটি name-এর জন্য ঠিক একটি v=spf1 record publish করুন। একই name-এ দুটি record থাকাও একটি permerror।
DKIM (domainkeys identified mail) relay-এর কাছে থাকা private key দিয়ে প্রতিটি message sign করে। Receiver-রা DNS থেকে সংশ্লিষ্ট public key সংগ্রহ করে। আপনার relay একটি selector এবং publish করার জন্য একটি TXT record অথবা CNAME দেবে:
sel1._domainkey.notify.example.com. IN CNAME sel1.dkim.relay.example.DKIM, SPF-এর চেয়ে বেশি গুরুত্বপূর্ণ। কারণ forwarding-এর পরেও DKIM কার্যকর থাকে। কোনো mailing list অথবা .forward rule আপনার message forward করলে সেটি forwarder-এর IP address থেকে আসে। ফলে SPF fail করে, কিন্তু signature তখনও verify হয়।
DMARC (domain-based message authentication, reporting and conformance) কোনো check align না করলে receiver-কে কী করতে হবে তা জানায় এবং তাদের report পাঠাতে বলে। এটি organisational domain-এ publish করুন:
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com; adkim=r; aspf=r"p=none দিয়ে শুরু করুন এবং দুই সপ্তাহ report পড়ুন। p=none delivery-তে কোনো পরিবর্তন করে না। এটি শুধু reporting চালু করে। এভাবেই বোঝা যায় কোন কোন system থেকে আপনি ভুলে গিয়েছিলেন যে আপনার domain ব্যবহার করে message পাঠানো হচ্ছে। এরপর p=quarantine-এ যান, তারপর p=reject-এ যান। প্রথম দিনেই p=reject publish করলে সাধারণত customer-এর কাছ থেকে জানতে হয় যে আপনার invoicing system domain ব্যবহার করে message পাঠাচ্ছিল এবং সেই customer invoice পায়নি।
আপনার DNS panel কী দেখাচ্ছে তা নয়, Internet-এ কী দেখা যাচ্ছে তা পরীক্ষা করুন:
dig +short TXT notify.example.com
dig +short TXT sel1._domainkey.notify.example.com
dig +short TXT _dmarc.example.comEmpty output-এর অর্থ record এখনও propagate হয়নি অথবা name ভুল। পাঁচ মিনিট আগে ঠিক করা একটি record আগের TTL (time to live)-এর মেয়াদ পর্যন্ত cache-এ ভুল অবস্থায় থাকতে পারে। তাই কোনো সিদ্ধান্তে পৌঁছানোর আগে TTL পরীক্ষা করুন।
From এবং Return-Path সামঞ্জস্যপূর্ণ রাখুন
প্রতিটি বার্তায় প্রেরকের দুটি ঠিকানা থাকে, এবং এগুলো ভিন্নভাবে যাচাই করা হয়। Envelope sender-কে SMTP MAIL FROM কমান্ডে দেওয়া হয় এবং delivered message-এ এটি Return-Path হিসেবে দেখা যায়। Header From হলো পাঠক যে ঠিকানাটি দেখেন।
SPF connecting IP address-এর বিপরীতে envelope sender-এর domain যাচাই করে। DKIM স্বাক্ষরকারী domain-কে d= হিসেবে জানায়। Header From-এর domain-এর সঙ্গে ওই দুটি domain-এর অন্তত একটির alignment থাকলেই DMARC pass করে। Relaxed alignment-এ (adkim=r, aspf=r, যা default) subdomain-ও গণ্য হয়। তাই notify.example.com-এর envelope sender, example.com-এর header From-এর সঙ্গে aligned হয়। Strict alignment-এ তা হয় না।
ব্যবহারিক নিয়মটি সংক্ষিপ্ত: header From এবং envelope sender একই domain-এ রাখুন। তাহলে এই প্রশ্ন ওঠে না। msmtp-তে set_from_header on এবং Postfix-এ sender_canonical_maps ঠিক এটাই করে।
Delivered message-এ verdict দেখুন। Gmail-এ "Show original" receiver যে header লিখেছে তা দেখায়:
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সেখানে তিনটি check-ই pass করেছে। অন্য যেকোনো ফলাফলে কোন check ব্যর্থ হয়েছে এবং সাধারণত কেন হয়েছে তা উল্লেখ থাকে। এই বিষয়টি debug করার জন্য এটিই সবচেয়ে দ্রুত পাওয়া তথ্য।
ভলিউম বাড়ার আগে bounce ও complaint সামলান
Bounce হলো receiver আপনার message প্রত্যাখ্যান করা। Hard bounce স্থায়ী, এবং Gmail এটিকে 550 5.1.1 The email account that you tried to reach does not exist হিসেবে উল্লেখ করে। Soft bounce সাময়িক। Full mailbox বা greylisting-এর ক্ষেত্রে এটি একটি 4xx code, এবং relay নিজে থেকেই আবার চেষ্টা করে।
Relay আপনার hard bounce rate পরিমাপ করে। যেসব account অস্তিত্বহীন address-এ বারবার mail পাঠায়, সেগুলো suspend করা হয়। কারণ এই pattern সাধারণত কেনা list-এর মতো দেখায়। Complaint আরও গুরুত্বপূর্ণ। Complaint হলো কোনো ব্যক্তি spam button চাপলে সেটি তৈরি হয়। Google-এর sender guidance (August 2026-এ পরীক্ষা করা) অনুযায়ী Postmaster Tools-এ রিপোর্ট করা spam rate 0.30%-এর নিচে রাখা উচিত। তারা 0.10%-এর নিচে রাখার পরামর্শও দেয়।
ভলিউম বাড়ার আগে এই চারটি ব্যবস্থা রাখুন:
- একটি webhook রাখুন, অথবা প্রতি সপ্তাহে relay-এর suppression list পরীক্ষা করুন, যাতে bounce দেখতে পান
- এমন একটি From address ব্যবহার করুন, যেটি সত্যিকারের mailbox এবং কেউ পড়ে; reply কোথায় যাবে তা নির্ধারণ করতে
Reply-Toসেট করুন - কোনো address কোনো কিছুর সঙ্গে যোগ করার আগে confirmation নিন, যাতে address-এর মালিক নিজে না দেওয়া address-এ কখনো mail না যায়
- যেকোনো form থেকে mail পাঠানো শুরু হলে সেখানে rate limit দিন
শেষের দুটি জায়গাতেই self-hosted app সাধারণত প্রথমে ব্যর্থ হয়। সুরক্ষাহীন signup form-এ যে কেউ অন্য ব্যক্তির address লিখতে পারে। আপনার server confirmation পাঠায়, এবং সেই ব্যক্তি message-টিকে spam হিসেবে চিহ্নিত করে। signup form-এ subscription bombing বন্ধ করা deliverability-এর কাজ হওয়ার পাশাপাশি abuse প্রতিরোধের কাজও।
এই path-এ bulk mail পাঠাবেন না। Newsletter-এর জন্য list management এবং unsubscribe header দরকার, যা transactional mail-এ সাধারণত থাকে না। তাই এগুলো নিজস্ব self-hosted Listmonk instance-এর মাধ্যমে চালান। এটিকে আলাদা subdomain এবং আলাদা reputation দিন। একটি self-hosted forum থেকে পাঠানো notification mail মাঝামাঝি ধরনের। এর ধরন transactional mail-এর মতো, কিন্তু volume bulk mail-এর মতো। আপনার setup কার্যকর কি না, সাধারণত এটিই প্রথম দেখায়।
তথ্য হিসেবে, Gmail-এর bulk sender rules প্রতিদিন Gmail address-এ 5,000-এর বেশি message পাঠানোর ক্ষেত্রে প্রযোজ্য। Marketing mail-এর জন্য SPF, DKIM, DMARC এবং one-click unsubscribe দরকার। অধিকাংশ self-hosted app কখনো এই সীমায় পৌঁছায় না। তবে এখন প্রত্যেক sender-এর কাছ থেকেই 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-এর বিরুদ্ধে credentials পরীক্ষা করে। আপনার অ্যাপগুলো যে পথ ব্যবহার করে, সেটি পরীক্ষা করতে host relay-এ নির্দেশ করুন:
swaks --to you@example.com --from apps@notify.example.com --server 127.0.0.1এরপর বাস্তব mail ব্যবহার করে সার্ভার থেকে end to end ফলাফল পরীক্ষা করুন। Configuration file দেখে এসবের কোনোটি প্রমাণ করা যায় না। তাই নিজেই পরীক্ষা চালান:
- mail-tester.com-এর মতো কোনো scoring service-এ mail পাঠান। এটি আপনার SPF, DKIM, DMARC এবং message content পড়ে এবং score-এর কারণগুলো জানায়
- আপনার ব্যবহারকারীরা যে দুই provider ব্যবহার করেন, তাদের প্রত্যেকটির একটি mailbox-এ mail পাঠান এবং raw message-এ
Authentication-Resultsপড়ুন - alignment result পরিষ্কার না হলে learndmarc.com-এ একটি message পরীক্ষা করুন
- শুধু command line থেকে নয়, অ্যাপ থেকেই send trigger করুন, কারণ From header অ্যাপই সেট করে
শেষে একটি বাস্তব সতর্কতা। সব তিনটি record সঠিক থাকলেও একেবারে নতুন domain-এর mail কখনো কখনো spam folder-এ যায়। এর কারণ, domainটির কোনো history নেই এবং receivers গত সপ্তাহে দেখা domain সম্পর্কে সতর্ক থাকে। শুরুতে অল্প mail পাঠান এবং মানুষ যে mail প্রত্যাশা করে, সেটিই পাঠান। এরপর reputation তৈরি হবে। কোনো configuration এই প্রক্রিয়াটি এড়িয়ে যেতে পারে না।
FAQ
VPS-এ outbound port 25 কেন blocked?
প্রায় সব provider ডিফল্টভাবে outbound TCP port 25 block করে, কারণ এই port খোলা থাকা একটি breached server থেকে receiving mail server-এ সরাসরি spam পাঠানো সম্ভব। Packet প্রত্যাখ্যান না করে drop করা হয়। তাই লক্ষণ হিসেবে error message না দেখিয়ে connection ঝুলে থাকে এবং পরে timeout হয়। nc -vz -w 5 gmail-smtp-in.l.google.com 25-এর পাশে nc -vz -w 5 smtp.relay.example 587 চালিয়ে এটি নিশ্চিত করুন: প্রথমটি অপেক্ষা করতে থাকে, দ্বিতীয়টি সঙ্গে সঙ্গে উত্তর দেয়। সমাধান হিসেবে block তুলে দেওয়ার অনুরোধ করবেন না। submission port 587 বা 465-এ থাকা relay ব্যবহার করে mail পাঠান। এই port-গুলো খোলা থাকে এবং authenticated client-এর জন্য নির্ধারিত।
কয়েকটি app notification পাঠানোর জন্যও কি SPF, DKIM এবং DMARC দরকার?
হ্যাঁ, এবং volume কম হলেও নিয়ম বদলায় না। Receiver-রা একটি password reset-এর ক্ষেত্রেও পঞ্চাশ হাজার message-এর campaign-এর মতো একই check প্রয়োগ করে। SPF এবং DKIM না থাকলে আপনার mail unauthenticated থাকে। Google-এর বর্তমান sender guidance অনুযায়ী প্রতিটি sender-এর জন্য অন্তত একটি থাকা দরকার। DMARC না থাকলে কোনো report পাবেন না। ফলে সমস্যার প্রথম ইঙ্গিত হতে পারে কোনো user জানাচ্ছেন যে reset link পৌঁছায়নি। তিনটিই DNS record। এগুলোর কোনো খরচ নেই, এবং publish করতে প্রায় দশ মিনিট লাগে।
Relay client হিসেবে msmtp নাকি Postfix ব্যবহার করা উচিত?
একজন ব্যক্তি যদি box administer করেন এবং relay outage-এর সময় message হারানো গ্রহণযোগ্য হয়, তাহলে msmtp ব্যবহার করুন। এতে একটি config file থাকে এবং কোনো daemon লাগে না। এটি queue করে না, তাই relay unreachable হলে message হারিয়ে যায়। কয়েক দিন ধরে retry করার মতো queue চাইলে, অথবা ভিন্ন system user হিসেবে একাধিক app চললে, Postfix-কে satellite হিসেবে ব্যবহার করুন। Postfix relay password এমন একটি root-only file-এ রাখে যা app-গুলো কখনো পড়ে না। অন্যদিকে, যে user send করে তার প্রত্যেকের জন্য msmtp-এর config readable হতে হয়।
আমার app-এর mail root থেকে আসছে বলে কেন reject হয়?
Cron job এবং অনেক app local user ও hostname থেকে sender তৈরি করে। ফলে root@srv1.localdomain-এর মতো address তৈরি হয়। এই address relay-এ verified নয়। তাই relay sender address উল্লেখ করে 553 বা 554 reply দিয়ে message প্রত্যাখ্যান করে। প্রতিটি app-এ আলাদা করে পরিবর্তন না করে host level-এ ঠিক করুন: /etc/msmtprc-এ একটি from address-সহ set_from_header on, অথবা Postfix-এ sender_canonical_classes = envelope_sender, header_sender-সহ sender_canonical_maps ব্যবহার করুন। Reply কোনো ব্যক্তির কাছে পৌঁছানো দরকার হলে প্রতিটি app-এর ভিতরে Reply-To set করুন।
App mail-এর জন্য আলাদা subdomain ব্যবহার করলে কি main domain সত্যিই সুরক্ষিত থাকে?
আংশিকভাবে, তবে এটি করা উপযোগী। Receiver-রা domain অনুযায়ী reputation track করে। তাই notify.example.com-এর বিরুদ্ধে complaint-এর প্রভাব মূলত notify.example.com-এর মধ্যেই থাকে, আর আপনার main domain mail deliver করতে থাকে। সীমাবদ্ধতাও আছে। কিছু receiver subdomain-এর signal organisational domain-এও প্রয়োগ করে। Organisational level-এ publish করা DMARC policy subdomain-এও প্রযোজ্য হয়, যদি আলাদাভাবে sp= set না করেন। তাই subdomain-কে ক্ষতি সীমিত করার ব্যবস্থা হিসেবে দেখুন, নিশ্চয়তা হিসেবে নয়।