SSD Nodes Learn Hosting plans →
নির্দেশিকা Matt Connorদ্বারা Matt Connor · আপডেট করা হয়েছে 2026-08-21

VPS-এ নিজের ডিসপোজেবল ইমেইল ইনবক্স সেটআপ করার নিয়ম

Docker Compose এবং Mailpit ব্যবহার করে কীভাবে নিজের VPS-এ একটি নিরাপদ টেস্ট ইমেইল ইনবক্স তৈরি করবেন তা জানুন। ভুলবশত গ্রাহকের কাছে মেইল যাওয়া রোধ করতে এই পদ্ধতিটি কার্যকর।

ডিসপোজেবল ইমেইল ইনবক্স কী

একটি ডিসপোজেবল ইমেইল ইনবক্স হলো একটি ছোট SMTP (simple mail transfer protocol) সার্ভার, যা যেকোনো ঠিকানার মেইল গ্রহণ করে কিন্তু তা কোথাও পাঠায় না। আপনার স্টেজিং অ্যাপ্লিকেশন কোনো প্রকৃত মেইল প্রোভাইডারের পরিবর্তে এখানে মেইল পাঠায় এবং প্রতিটি বার্তা সেখানেই আটকে থাকে। আপনি একটি ওয়েব ইন্টারফেসের মাধ্যমে মেইলগুলো পড়তে পারেন, তাই ভুল প্রাপকের তালিকা বা ত্রুটিপূর্ণ টেমপ্লেটের কারণে কোনো সমস্যা হয় না, কারণ মেইলটি কখনোই এই ইনবক্সের বাইরে যায় না।

এই নির্দেশিকাটি একটি একক VPS-এ Docker Compose ব্যবহার করে এমন একটি ইনবক্স তৈরি করার প্রক্রিয়া দেখায়। Mailpit এখানে ক্যাচ-অল সিঙ্ক হিসেবে কাজ করে। এর SMTP লিসেনার এমনভাবে বাইন্ড করা থাকে যাতে শুধুমাত্র আপনার অ্যাপ্লিকেশনই সেখানে পৌঁছাতে পারে। এর ওয়েব ইন্টারফেসটি nginx-এর পেছনে transport layer security (TLS) এবং একটি পাসওয়ার্ড দিয়ে সুরক্ষিত থাকে এবং একটি রিটেনশন লিমিট ডিস্ক পূর্ণ হওয়া থেকে রক্ষা করে। আপনি যদি Compose-এর সাথে পরিচিত না হন, তবে the Compose basics for a VPS নিবন্ধটি দেখুন, যেখানে এই নির্দেশিকায় ব্যবহৃত ফাইল লেআউট সম্পর্কে আলোচনা করা হয়েছে।

এর ফলাফল একটি টেস্ট টুল, কোনো মেইল সার্ভার নয়। এতে কোনো অ্যাকাউন্ট, ডেলিভারি বা স্প্যাম ফিল্টারিং নেই। প্রকৃত ব্যবহারকারীদের জন্য আসল মেইলবক্স তৈরি করা a full mail server such as Mailcow ব্যবহারের মতো একটি অনেক বড় কাজ।

Mailpit বনাম Inbucket বনাম MailHog: কোন sink-টি চালাবেন

এই কাজটি করার জন্য তিনটি টুল রয়েছে। রক্ষণাবেক্ষণের অবস্থা, তারা যে পোর্টে লিসেন (listen) করে এবং মেসেজ গ্রহণ করার পর তারা কী করতে পারে—তার ভিত্তিতে এদের পার্থক্য করা হয়। নিচের সংস্করণগুলো আগস্ট 2026-এ যাচাই করা হয়েছে।

MailHog (mailhog/mailhog) SMTP-এর জন্য 1025 পোর্টে লিসেন করে এবং 8025 পোর্টে এর ইন্টারফেস প্রদর্শন করে। এটি এখনও কাজ করে। এর ডিফল্ট ব্রাঞ্চে আগস্ট 2022 থেকে কোনো কমিট (commit) করা হয়নি এবং ট্র্যাকারটিতে 250টিরও বেশি ওপেন ইস্যু রয়েছে, তাই আপনি আপনার টেস্ট পাথে আনপ্যাচড ডিপেন্ডেন্সি (unpatched dependencies) চালাবেন। এটি দিয়ে নতুন কোনো কাজ শুরু করবেন না।

Inbucket (inbucket/inbucket) SMTP-এর জন্য 2500 পোর্টে, ওয়েব ইন্টারফেসের জন্য 9000 পোর্টে এবং POP3 (post office protocol version 3)-এর জন্য 1100 পোর্টে লিসেন করে। ডিসেম্বর 2025-এ এর 3.1.1 সংস্করণটি রিলিজ হয়েছে। এটি মেসেজগুলোকে /storage-এর অধীনে ফাইল হিসেবে সংরক্ষণ করে এবং নিজেই সেগুলো মুছে ফেলে: ইমেজটি INBUCKET_STORAGE_RETENTIONPERIOD=72h এবং INBUCKET_STORAGE_MAILBOXMSGCAP=300 সেট করে। যখন কোনো টেস্টে HTTP কলের পরিবর্তে POP3 ক্লায়েন্ট লাইব্রেরি ব্যবহার করে মেইল সংগ্রহ করার প্রয়োজন হয়, তখন এটি বেছে নিন।

Mailpit (axllent/mailpit) MailHog-এর মতোই 1025 এবং 8025 পোর্ট ব্যবহার করে, তাই অ্যাপ্লিকেশন কনফিগারেশনে কোনো পরিবর্তন না করেই এটি MailHog-এর জায়গা নিতে পারে। 8 আগস্ট 2026-এ 1.30.7 সংস্করণটি রিলিজ হয়েছে। এই গাইডের যা প্রয়োজন তা এটি বাইনারির ভেতরেই বহন করে: ওয়েব ইন্টারফেস এবং API (application programming interface)-এর জন্য একটি পাসওয়ার্ড ফাইল, মেসেজ ক্যাপ, এজ ক্যাপ এবং রিসিভিয়েন্ট ফিল্টার। এই গাইডের বাকি অংশে Mailpit ব্যবহার করা হয়েছে।

ক্যাচ-অল (catch-all) যেভাবে কাজ করে এবং কেন এতে DNS-এর কোনো ভূমিকা নেই

আপনার অ্যাপ্লিকেশন এখানে ইমেইল পাঠানোর গন্তব্য খোঁজে না। আপনি এটিকে একটি host এবং একটি port প্রদান করেন, এটি একটি TCP সংযোগ খোলে এবং RCPT TO:<anyone@example.test> ঘোষণা করে। Mailpit সেই প্রাপককে গ্রহণ করে, বার্তাটি সংরক্ষণ করে এবং কোথাও ফরোয়ার্ড করে না। ডোমেইনটি কখনোই resolve করা হয় না, তাই example.test কাজ করে যদিও .test একটি সংরক্ষিত নাম যা ডোমেইন নেম সিস্টেমে (DNS) কোথাও নেই।

এটিই সম্পূর্ণ প্রক্রিয়া এবং এই কারণেই ইনবক্সটি ডিফল্টভাবে নিরাপদ। এতে কোনো MX (mail exchanger) রেকর্ডের প্রয়োজন হয় না, কোনো ডেলিভারির চেষ্টা করা হয় না এবং কোনো বার্তাই কোনো প্রকৃত ব্যক্তির কাছে পৌঁছাতে পারে না।

আপনার স্টেজ অ্যাপটিকে সিঙ্কের দিকে নির্দেশ করুন

অ্যাপটি যখন একই Compose প্রজেক্টে কন্টেইনার হিসেবে চলে, তখন এর SMTP host-কে mailpit-এ সেট করুন। আর যখন এটি হোস্ট মেশিনে চলে, তখন এটিকে 127.0.0.1-এ সেট করুন। পোর্ট হিসেবে 1025 ব্যবহার করুন, TLS বন্ধ রাখুন এবং ইউজারনেম ও পাসওয়ার্ডের ঘর খালি রাখুন। Mailpit বেনামী ইমেইল গ্রহণ করে।

কিছু ফ্রেমওয়ার্ক ক্রেডেনশিয়াল ছাড়া ইমেইল পাঠাতে চায় না। MP_SMTP_AUTH_ACCEPT_ANY=1 ব্যবহার করলে Mailpit যেকোনো ইউজারনেম ও পাসওয়ার্ড গ্রহণ করবে এবং MP_SMTP_AUTH_ALLOW_INSECURE=1 এনক্রিপশনবিহীন সংযোগে PLAIN ও LOGIN মেকানিজম ব্যবহারের অনুমতি দেবে। এই দুটি সেটিংস এখানে নিরাপদ, কারণ লিসেনারটি ইন্টারনেট থেকে অ্যাক্সেস করা যায় না, যা নিচের ডেপ্লয়মেন্টে নিশ্চিত করা হয়েছে।

প্রথম দিন থেকেই MP_SMTP_ALLOWED_RECIPIENTS সেট করা বুদ্ধিমানের কাজ। এটি একটি রেগুলার এক্সপ্রেশন গ্রহণ করে এবং যে প্রাপক এই এক্সপ্রেশনের সাথে মেলে না, তাদের সবাইকে প্রত্যাখ্যান করে। এটিকে আপনার টেস্ট ডোমেইনের দিকে নির্দেশ করুন। এতে কোনো স্টেজ ডাটাবেসে যদি আসল গ্রাহকের ঠিকানা থেকে যায়, তবে সেটি চুপচাপ সিঙ্কে জমা না হয়ে আপনার অ্যাপ্লিকেশনের লগে একটি দৃশ্যমান ত্রুটি তৈরি করবে।

Docker Compose ফাইল

প্রথমে ডিরেক্টরি তৈরি করুন এবং ওয়েব ইন্টারফেসের জন্য একটি পাসওয়ার্ড ফাইল তৈরি করুন। htpasswd -B একটি bcrypt হ্যাশ লেখে এবং Mailpit bcrypt-এর পাশাপাশি প্লেইন টেক্সটও পড়তে পারে।

mkdir -p ~/mailpit/data
cd ~/mailpit
sudo apt update && sudo apt install -y apache2-utils
htpasswd -B -c data/ui-auth qa

compose.yaml লিখুন:

services:
  mailpit:
    image: axllent/mailpit:v1.30
    container_name: mailpit
    restart: unless-stopped
    ports:
      - "127.0.0.1:8025:8025"
      - "127.0.0.1:1025:1025"
    volumes:
      - ./data:/data
    environment:
      MP_DATABASE: /data/mailpit.db
      MP_MAX_MESSAGES: 2000
      MP_MAX_AGE: 14d
      MP_UI_AUTH_FILE: /data/ui-auth
      MP_SMTP_AUTH_ACCEPT_ANY: 1
      MP_SMTP_AUTH_ALLOW_INSECURE: 1
      MP_SMTP_ALLOWED_RECIPIENTS: '@example\.test$$'

ডাবল ডলার সাইন কোনো ভুল নয়। Compose একটি একক $-কে ভেরিয়েবল এক্সপ্যানশনের শুরু হিসেবে গণ্য করে, তাই $$ ব্যবহার করে আপনি কন্টেইনারের ভেতর একটি লিটারেল ডলার সাইন পাঠাতে পারেন। রেজেক্স (regex) Mailpit-এর কাছে @example\.test$ হিসেবে পৌঁছায়।

এটি চালু করুন এবং হেলথ স্টেট পরীক্ষা করুন:

docker compose up -d
docker compose ps

STATUS কলামে Up ... (healthy) লেখা থাকা উচিত। ইমেজটিতে নিজস্ব হেলথচেক রয়েছে যা প্রতি 15 সেকেন্ডে /mailpit readyz চালায়, তাই যে কন্টেইনার starting অবস্থায় থাকে বা unhealthy হয়ে যায়, সেটি কন্টেইনারের ভেতরে 8025 পোর্টে সেবা দিচ্ছে না। অন্য কিছু পরিবর্তন করার আগে docker compose logs mailpit পড়ুন।

উভয় পাবলিশড পোর্টের সাথেই একটি অ্যাড্রেস থাকে এবং সেই অ্যাড্রেসটিই হলো নিরাপত্তা নিয়ন্ত্রণ। কন্টেইনারের ভেতরে Mailpit 0.0.0.0-এ লিসেন করে, যা ঠিক আছে, কারণ কন্টেইনারের নিজস্ব নেটওয়ার্ক নেমস্পেস রয়েছে। ম্যাপিংয়ের বাম দিকের অংশটি নির্ধারণ করে বাইরে থেকে কে এটি অ্যাক্সেস করতে পারবে। 8025:8025 লিখুন এবং Docker হোস্টের প্রতিটি অ্যাড্রেসে বাইন্ড করবে, যার মধ্যে পাবলিক অ্যাড্রেসটিও অন্তর্ভুক্ত।

যদি আপনার স্টেজিং অ্যাপটি একই ফাইলে একটি সার্ভিস হিসেবে থাকে, তবে 1025 ম্যাপিংটি সম্পূর্ণ মুছে ফেলুন এবং অ্যাপটিকে 1025 পোর্টে mailpit হোস্টনামের দিকে নির্দেশ করুন। একটি শেয়ার্ড Compose নেটওয়ার্কে থাকা কন্টেইনারগুলো সরাসরি একে অপরের সাথে যোগাযোগ করতে পারে, তাই SMTP পোর্টটি হোস্টের সংস্পর্শে আসার প্রয়োজনই হয় না। Compose নেটওয়ার্ক কীভাবে সার্ভিস নাম রিজলভ করে বিষয়টি সেখানে বিস্তারিত আলোচনা করা হয়েছে।

একটি মেসেজ পাঠান এবং সেটি পৌঁছেছে কি না যাচাই করুন

python3 - <<'EOF'
import smtplib
from email.message import EmailMessage

m = EmailMessage()
m["From"] = "staging@example.test"
m["To"] = "anyone@example.test"
m["Subject"] = "Mailpit smoke test"
m.set_content("If this appears in the web interface, the sink works.")
with smtplib.SMTP("127.0.0.1", 1025) as s:
    s.send_message(m)
EOF

সফল হলে স্ক্রিপ্টটি কোনো আউটপুট দেখায় না। API-এর মাধ্যমে মেসেজটি সংরক্ষিত হয়েছে কি না তা নিশ্চিত করুন:

curl -s -u qa:yourpassword http://127.0.0.1:8025/api/v1/messages

এটি সংরক্ষিত মেসেজগুলোর একটি JSON তালিকা প্রদান করবে। -u ফ্ল্যাগটি বাদ দিলে অনুরোধটি প্রত্যাখ্যান করা হবে, কারণ MP_UI_AUTH_FILE একই সাথে API এবং ওয়েব ইন্টারফেসকে সুরক্ষিত রাখে। ইনবক্স রিড করে এমন যেকোনো টেস্টের ক্ষেত্রেও এই ক্রেডেনশিয়ালগুলো পাঠাতে হবে।

Python স্ক্রিপ্ট থেকে একটি ConnectionRefusedError আসার অর্থ হলো 127.0.0.1:1025-এ কোনো কিছু লিসেন করছে না। আপনি যদি SMTP ম্যাপিং সরিয়ে ফেলেন তবে এটিই প্রত্যাশিত ফলাফল, এবং সেক্ষেত্রে চেকটি একই Compose নেটওয়ার্কের একটি কন্টেইনার থেকে চালাতে হবে।

nginx-এর মাধ্যমে পাসওয়ার্ডসহ ওয়েব ইন্টারফেস প্রকাশ করা

ইন্টারফেসটি বর্তমানে শুধুমাত্র loopback ঠিকানায় সাড়া দেয়। nginx TLS টার্মিনেশন সম্পন্ন করে এবং কোনো অনুরোধ সেখানে পৌঁছানোর আগেই পাসওয়ার্ড চায়।

sudo htpasswd -B -c /etc/nginx/mailpit.htpasswd qa
server {
    listen 443 ssl;
    server_name mail-test.example.com;

    ssl_certificate     /etc/letsencrypt/live/mail-test.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mail-test.example.com/privkey.pem;

    auth_basic           "mailpit";
    auth_basic_user_file /etc/nginx/mailpit.htpasswd;

    location / {
        proxy_pass http://127.0.0.1:8025;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

sudo nginx -t && sudo systemctl reload nginx দিয়ে সিনট্যাক্স পরীক্ষা করার পর রিলোড করুন। আপনি যদি প্রথমবারের মতো প্রক্সি ব্যবহার করেন, তবে রিভার্স প্রক্সি ব্লকের প্রতিটি ডিরেক্টিভ কী কাজ করে তা একবার পড়ে নেওয়া ভালো।

nginx ফাইল এবং data/ui-auth-এ একই ইউজারনেম ও পাসওয়ার্ড ব্যবহার করুন। nginx ব্রাউজারের Authorization হেডারটি আপস্ট্রিমে ফরোয়ার্ড করে, তাই একই ক্রেডেনশিয়াল ব্যবহার করলে একটি প্রম্পটেই উভয় যাচাইকরণ সম্পন্ন হয়। ভিন্ন ক্রেডেনশিয়াল ব্যবহার করলে ব্রাউজার একটি সেট ধরে রাখে যা দ্বিতীয় যাচাইকরণে প্রত্যাখ্যাত হয়।

Upgrade এবং Connection হেডারগুলো কেবল সাজানোর জন্য নয়। Mailpit একটি খোলা পৃষ্ঠায় WebSocket-এর মাধ্যমে নতুন মেইল পাঠায়, এবং এই হেডারগুলো ছাড়া HTTP/1.1 প্রক্সি সংযোগ আপগ্রেড করতে পারে না। সেক্ষেত্রে পৃষ্ঠাটি সঠিকভাবে লোড হলেও আপডেট হয় না: মেইল আসে, API তা দেখায়, কিন্তু আপনি রিলোড না করা পর্যন্ত তালিকাটি স্থির থাকে।

উভয় সুরক্ষাই বজায় রাখুন। nginx পাসওয়ার্ড পাবলিক অ্যাড্রেসকে সুরক্ষিত রাখে এবং MP_UI_AUTH_FILE সরাসরি 8025 পোর্টকে সুরক্ষিত রাখে। এটি অত্যন্ত গুরুত্বপূর্ণ, কারণ আপনার স্টেজিং অ্যাপ থেকে তৈরি করা প্রতিটি পাসওয়ার্ড রিসেট লিঙ্ক এই ইন্টারফেসে দেখা সম্ভব।

সিঙ্ককে কখনোই ওপেন রিলে হতে দেবেন না

একটি ওপেন রিলে হলো এমন একটি SMTP সার্ভার, যা যেকোনো ব্যক্তির কাছ থেকে বার্তা গ্রহণ করে এবং যেকোনো গন্তব্যে তা পাঠিয়ে দেয়। স্প্যামাররা সবসময় এ ধরনের সার্ভার খুঁজে বেড়ায় এবং আপনার ঠিকানায় একটি ওপেন রিলে পাওয়া গেলে তা থেকে প্রচুর অপব্যবহারের রিপোর্ট আসবে এবং আপনার অ্যাকাউন্ট স্থগিত হয়ে যেতে পারে।

Mailpit ডিফল্টভাবে কোনো ওপেন রিলে নয়, কারণ এটি কখনোই বার্তা ফরোয়ার্ড করে না। আপনি যতক্ষণ না MP_SMTP_RELAY_CONFIG-কে কোনো রিলে কনফিগারেশন ফাইলের দিকে নির্দেশ করছেন, ততক্ষণ রিলে সুবিধাটি বন্ধ থাকে এবং ইন্টারফেসে রিলিজ অ্যাকশনটি কোনো কাজ করে না। এটি সেট না রাখা একটি সচেতন সিদ্ধান্ত।

এই বৈশিষ্ট্যটি হারানোর দুটি উপায় আছে। একটি রিলে কনফিগার করুন যাতে রিলিজ বাটন কাজ করে এবং তারপর SMTP পোর্টটি ইন্টারনেটের জন্য উন্মুক্ত করে দিন, তাহলেই আপনি একটি কার্যকর ওপেন রিলে তৈরি করে ফেললেন। রিলে ছাড়া পোর্ট উন্মুক্ত করলে অপরিচিতরা আপনার মাধ্যমে মেইল পাঠাতে পারবে না, কিন্তু তারা আপনার স্টোরেজ পূর্ণ করে ফেলতে পারবে এবং আপনার টিমের বিশ্বাসযোগ্য ইন্টারফেসে কন্টেন্ট যুক্ত করতে পারবে।

Docker হোস্টের ক্ষেত্রে প্রধান সমস্যা হলো ফায়ারওয়াল। পোর্ট পাবলিশ করলে Docker নিজে থেকেই nat টেবিলে নিজস্ব রুল লিখে ফেলে, এবং ufw (uncomplicated firewall) রুল কার্যকর হওয়ার আগেই কন্টেইনারের উদ্দেশ্যে আসা ট্রাফিক সেখানে ম্যাচ হয়ে যায়। sudo ufw deny 1025/tcp সফল হওয়ার রিপোর্ট দিলেও বাস্তবে কোনো পরিবর্তন হয় না। কেন Docker ufw-এর বাইরে সরাসরি পোর্ট পাবলিশ করে নিবন্ধে চেইন অর্ডারের বিষয়টি বিস্তারিত আলোচনা করা হয়েছে।

এর সমাধান হলো ফায়ারওয়াল রুল নয়, বরং ম্যাপিংয়ের ঠিকানা ঠিক করা। কী বাইন্ড করা আছে তা পরীক্ষা করুন:

sudo ss -ltnp | grep -E ':(1025|8025)'

সঠিক আউটপুটে 127.0.0.1:1025 এবং 127.0.0.1:8025 দেখা যাবে। যদি কোনো লাইনে 0.0.0.0:1025 লেখা থাকে, তবে বুঝতে হবে ম্যাপিং তার ঠিকানা হারিয়েছে এবং সিঙ্কটি ইন্টারনেটের জন্য লিসেন করছে। অন্য কোনো মেশিন থেকে nc -vz mail-test.example.com 1025 কমান্ডটি দিলে তা টাইম-আউট হওয়া উচিত অথবা সংযোগ প্রত্যাখ্যান করা উচিত।

যখন অ্যাপ্লিকেশনটি অন্য কোনো সার্ভারে থাকে, তখন দুটির মধ্যে সংযোগ স্থাপনের জন্য 1025 পোর্ট খুলবেন না। উভয় মেশিনকে একটি প্রাইভেট নেটওয়ার্ক বা VPN টানেলে রাখুন এবং ম্যাপিংটিকে সেই ইন্টারফেসের ঠিকানায় বাইন্ড করুন।

শুধুমাত্র প্রকৃত ইনবাউন্ড মেইল পেতে চাইলে MX রেকর্ড প্রকাশ করুন

একটি MX (mail exchanger) রেকর্ড অন্য মেইল সার্ভারগুলোকে জানায় যে কোন হোস্ট একটি ডোমেইনের জন্য মেইল গ্রহণ করে। আপনার অস্থায়ী ডোমেইনে কোনো MX রেকর্ড না থাকলে ইন্টারনেট থেকে কোনো মেইল আসতে পারবে না, কারণ প্রেরক সার্ভারগুলো মেইল ডেলিভারি করার কোনো ঠিকানা খুঁজে পাবে না। ইনবক্সে শুধুমাত্র আপনার নিজস্ব অ্যাপ্লিকেশনগুলো থেকে পাঠানো মেইল জমা হবে, যা একটি টেস্ট মেইলবক্সের মূল উদ্দেশ্য।

প্রকৃত মেইল গ্রহণ করার অর্থ হলো একটি MX রেকর্ড যা আপনার সার্ভারকে নির্দেশ করছে, Mailpit যা পোর্ট 25 (MP_SMTP_BIND_ADDR=0.0.0.0:25)-এ লিসেন করছে এবং সেই পোর্টটি খোলা রাখা। এই মুহূর্তে আপনি আপনার ডোমেইনের প্রতিটি ঠিকানার জন্য একটি পাবলিক ক্যাচ-অল (catch-all) সার্ভিস চালাচ্ছেন। এর পরবর্তী ফলাফলগুলো সম্পর্কে সচেতন থাকুন।

  • রেকর্ডটি পাবলিশ করার কয়েক দিনের মধ্যেই স্প্যাম আসা শুরু হয়, কারণ হার্ভেস্টাররা DNS রিড করে। ডিকশনারি অ্যাটাকগুলো তখন সাধারণ নামগুলো ব্যবহার করে প্রতিটি প্রচেষ্টার জন্য একটি করে মেসেজ জমা করে।
  • অপরিচিতদের পাঠানো অ্যাটাচমেন্ট আপনার ডিস্কে জমা হয় এবং সেখানেই থেকে যায়। এগুলো ফিল্টার করার কোনো ব্যবস্থা নেই, তাই অজানা প্রেরকের পাঠানো আর্কাইভ আপনার নিজস্ব টেস্ট মেইলের পাশেই জমা থাকে।
  • যে কেউ আপনার ডোমেইন সম্পর্কে জানলে তারা সেই ডোমেইনের কোনো ঠিকানা ব্যবহার করে থার্ড-পার্টি সার্ভিসে সাইন আপ করতে পারে এবং কনফার্মেশন মেইলটি আপনার সার্ভারে চলে আসবে। যদি পাসওয়ার্ড সুরক্ষায় কোনো ত্রুটি থাকে, তবে সেই অ্যাকাউন্টগুলোর নিয়ন্ত্রণ যে কেউ নিতে পারে যে ইনবক্সটি পড়ছে।
  • রিটেনশন লিমিট তখন আর সাধারণ রক্ষণাবেক্ষণের বিষয় থাকে না, বরং এটি একটি গুরুত্বপূর্ণ লোড ম্যানেজমেন্টে পরিণত হয়, কারণ মেইলের পরিমাণ এখন আর আপনার নিয়ন্ত্রণে নেই।

যদি ডেলিভারেবিলিটি চেক করার জন্য আপনার প্রকৃত ইনবাউন্ড মেইলের প্রয়োজন হয়, তবে একটি ডেডিকেটেড সাবডোমেইন ব্যবহার করুন, MP_MAX_AGE-এর মেয়াদ সংক্ষিপ্ত রাখুন এবং এর ভেতরের সবকিছুকে পাবলিক হিসেবে বিবেচনা করুন। যদি এমন মেইলবক্সের প্রয়োজন হয় যার ওপর মানুষ নির্ভর করতে পারে, তবে ফিল্টারিং এবং ব্যাকআপসহ একটি প্রকৃত মেইল সার্ভার ব্যবহার করুন।

Retention: একটি অসীম ক্যাচ-অল (catch-all) কীভাবে ডিস্ক পূর্ণ করে

Mailpit ডিফল্টভাবে 500টি মেসেজ সংরক্ষণ করে এবং এর বেশি হলে পর্যায়ক্রমে সবচেয়ে পুরনো মেসেজগুলো মুছে ফেলে। MP_MAX_MESSAGES: 0 স্বয়ংক্রিয়ভাবে মুছে ফেলার প্রক্রিয়াটি পুরোপুরি বন্ধ করে দেয়, আর এই একটি পরিবর্তনের কারণেই কোনো সতর্কতা ছাড়াই একটি ক্যাচ-অল ডিস্ক পূর্ণ করে ফেলতে পারে। MP_MAX_AGE একটি সময়সীমা যুক্ত করে যা ঘণ্টা বা দিন হিসেবে কাজ করে, যেমন 36h অথবা 14d

MP_DATABASE নির্ধারণ করে যে এই ডেটার কোনো অংশ টিকে থাকবে কি না। এটি ছাড়া, Mailpit একটি অস্থায়ী ফাইলে লেখে যা প্রসেস বন্ধ হওয়ার সাথে সাথে মুছে যায়, ফলে প্রতিটি রিস্টার্টের পর ইনবক্স খালি হয়ে যায়। এটি থাকলে, মেইল রিস্টার্টের পরেও টিকে থাকে এবং ফাইলটির আকার বাড়তে থাকে।

অ্যাটাচমেন্টগুলোই মূলত জায়গা দখল করে। একটি নাইটলি জব যা 300টি টেস্ট অ্যাড্রেসে 2 MB-এর PDF রিপোর্ট পাঠায়, তা প্রতি রাতে 600 MB জায়গা নেয় এবং শুধুমাত্র মেসেজ কাউন্টের সীমা দিয়ে এটি নিয়ন্ত্রণ করা সম্ভব নয়। এই বৃদ্ধির হিসাবটি সেই ভলিউমের অন্যান্য ডেটার সাথে মিলিয়ে করুন, কারণ PhotoPrism বা Immich-এর মতো মিডিয়া-নির্ভর অ্যাপ্লিকেশনগুলো ছোট VPS ডিস্কের বেশিরভাগ অংশ আগেই দখল করে রাখতে পারে।

du -h ~/mailpit/data/mailpit.db
df -h /

ক্যাপ ট্রিগার হওয়ার জন্য অপেক্ষা না করে CI রানগুলোর মাঝে স্টোরটি খালি করুন:

curl -s -u qa:yourpassword -X DELETE http://127.0.0.1:8025/api/v1/messages

Inbucket একই সমস্যা সমাধান করে INBUCKET_STORAGE_RETENTIONPERIOD (ইমেজে 72 ঘণ্টা) এবং INBUCKET_STORAGE_MAILBOXMSGCAP (300) এর মাধ্যমে। আপনি যা-ই ব্যবহার করুন না কেন, প্রথম টেস্ট সুইট পয়েন্ট করার আগেই সীমা নির্ধারণ করে নিন।

আপনার টেস্ট স্যুট থেকে ইনবক্স পড়া

GET /api/v1/messages কী কী সংরক্ষিত আছে তার তালিকা দেয়, GET /api/v1/message/{ID} একটি মেসেজ তার অংশ এবং হেডারসহ ফেরত দেয়, GET /api/v1/search ফিল্টার করে এবং DELETE /api/v1/messages স্টোরটি খালি করে দেয়। আপনি যে ভার্সনটি চালাচ্ছেন তার ইন্টারঅ্যাক্টিভ ডকুমেন্টেশন http://127.0.0.1:8025/api/v1/-এ পাওয়া যাবে।

একটি কার্যকর টেস্ট প্রথমে একটি মেসেজ পাঠায়, সেটি না আসা পর্যন্ত পোল (poll) করে, এরপর সাবজেক্ট এবং তার ভেতরের লিঙ্কটি যাচাই করে সব মুছে ফেলে। একটি মাত্র রিকোয়েস্ট না পাঠিয়ে ছোট একটি রিট্রাই লুপে পোল করুন, কারণ যে অ্যাপ্লিকেশন ব্যাকগ্রাউন্ড ওয়ার্কারে মেইল কিউ (queue) করে, সেটি Mailpit-এ মেসেজ পৌঁছানোর আগেই সেন্ড কল থেকে ফেরত আসে। একই প্যাটার্ন সেলফ-হোস্টেড এপিআই টেস্টিং এবং মকিং টুলস-এ দেখা যায়, যা সাধারণত স্টেজিং এনভায়রনমেন্টের অন্য অর্ধেক অংশ এবং এটি কখনোই প্রোডাকশন এনভায়রনমেন্টকে স্পর্শ করে না।

FAQ

একটি self-hosted disposable email inbox কি একটি open relay?

relay বন্ধ থাকলে এটি open relay নয়। Mailpit বার্তাগুলো জমা রাখে এবং যতক্ষণ না আপনি MP_SMTP_RELAY_CONFIG-কে একটি relay configuration-এর দিকে নির্দেশ করছেন, ততক্ষণ পর্যন্ত এটি কোনো বার্তা forward করে না। তাই কোনো অপরিচিত ব্যক্তি port 1025-এ পৌঁছালেও আপনার সার্ভারের মাধ্যমে মেইল পাঠাতে পারবে না। তবে তারা আপনার স্টোরেজ পূর্ণ করে ফেলতে পারে, তাই SMTP port-টিকে এমন একটি ঠিকানায় bind করুন যেখানে শুধুমাত্র আপনার অ্যাপ্লিকেশন পৌঁছাতে পারে। Compose-এ এটিকে 1025:1025 হিসেবে প্রকাশ করলে তা প্রতিটি host ঠিকানাকে bind করে, এবং sudo ufw deny 1025/tcp এটিকে বন্ধ করবে না, কারণ Docker-এর নিজস্ব nat rule-গুলো সবার আগে কার্যকর হয়।

আমার test domain-এর জন্য কি কোনো MX record প্রয়োজন?

শুধুমাত্র যদি আপনি ইন্টারনেট থেকে মেইল গ্রহণ করতে চান। MX record ছাড়া, প্রেরক সার্ভারগুলোর মেইল পৌঁছে দেওয়ার কোনো গন্তব্য থাকে না, তাই inbox-এ শুধুমাত্র আপনার নিজস্ব অ্যাপ্লিকেশনগুলো SMTP-এর মাধ্যমে যা পাঠায় তা-ই জমা হয়। record প্রকাশ করুন এবং port 25 খুলে দিন, তবে মনে রাখবেন আপনি তখন একটি public catch-all চালাচ্ছেন: কয়েক দিনের মধ্যেই spam আসবে, dictionary attack-এর মাধ্যমে প্রতিটি প্রচেষ্টার জন্য একটি করে বার্তা জমা হবে এবং কোনো ফিল্টারিং ছাড়াই অপরিচিতদের পাঠানো attachment আপনার ডিস্কে জমা হবে।

পেজ reload না করলে মেসেজ লিস্ট আপডেট হয় না কেন?

Mailpit একটি WebSocket-এর মাধ্যমে খোলা পেজে নতুন মেইল পাঠায়। একটি nginx location block-এ proxy_http_version 1.1 এবং UpgradeConnection header-এর অভাব থাকলে সেই connection upgrade হতে পারে না, ফলে পেজটি স্বাভাবিকভাবে লোড হয় কিন্তু তারপর আর আপডেট হয় না। মেইল ঠিকই পৌঁছায় এবং API-ও তা ফেরত দেয়, যার কারণে inbox-কে অচল মনে হয়। এই লাইনগুলো যোগ করুন, nginx reload করুন, তারপর পেজটি পুনরায় লোড করুন।

ডিস্ক পূর্ণ হওয়া থেকে inbox-কে কীভাবে আটকাব?

MP_MAX_MESSAGES-কে একটি বাস্তব সংখ্যায় রাখুন এবং MP_MAX_AGE যোগ করুন। ডিফল্ট সীমা হলো 500টি বার্তা, এবং এটিকে 0 সেট করলে মুছে ফেলার প্রক্রিয়াটি পুরোপুরি বন্ধ হয়ে যায়, যার ফলে attachment-সহ একটি catch-all inbox নীরবে বড় হতে থাকে। MP_MAX_AGE ঘণ্টা বা দিন হিসেবে সময় গ্রহণ করে, যেমন 36h বা 14d। CI teardown-এর সময় curl -X DELETE http://127.0.0.1:8025/api/v1/messages ব্যবহার করে স্টোর খালি করুন। Inbucket-এ একই কাজ করার জন্য INBUCKET_STORAGE_RETENTIONPERIOD (72h) এবং INBUCKET_STORAGE_MAILBOXMSGCAP (300) ব্যবহার করা হয়।

আমার কি Mailpit, Inbucket নাকি MailHog ব্যবহার করা উচিত?

আগস্ট 2026 অনুযায়ী, নতুন কাজের জন্য Mailpit ব্যবহার করুন। MailHog এখনো চলে, কিন্তু এর ডিফল্ট branch-এ আগস্ট 2022 থেকে কোনো commit আসেনি, তাই এটি unpatched dependency নিয়ে কাজ করে। Inbucket সক্রিয়ভাবে রক্ষণাবেক্ষণ করা হয় (3.1.1, ডিসেম্বর 2025) এবং যখন কোনো টেস্টের জন্য POP3 প্রয়োজন হয় তখন এটিই ভালো পছন্দ, কারণ Mailpit-এর POP3 সার্ভার শুধুমাত্র তখনই চালু হয় যখন আপনি সেটিকে একটি password file দেন। Mailpit, MailHog-এর মতোই 1025 এবং 8025 port ব্যবহার করে, তাই MailHog প্রতিস্থাপন করতে আপনার Compose ফাইলে শুধুমাত্র একটি image-এর নাম পরিবর্তন করলেই চলে।