সরাসরি পর্বে যান
পর্ব ৩৯ · ৬২-এর মধ্যে · মডিউল ৬

ইমেইল — SMTP, IMAP আর SPF, DKIM, DMARC

Email — MUA/MSA/MTA, MX Records, the SMTP Dialogue, MIME & Base64, POP3 vs IMAP, and SPF, DKIM & DMARC

Taught in Bangla, this lesson follows an email end to end: MUA, MSA and MTA roles, MX lookup, the SMTP dialogue and reply codes, envelope versus header addresses and BCC, MIME and Base64 attachments, POP3 versus IMAP, and sender authentication with SPF, DKIM and DMARC.

এই পর্বে যা শিখবেন

  • ইমেইল ব্যবস্থার অংশগুলো — MUA, MSA, MTA, MDA আর mailbox — আর alice@example.com থেকে bob@example.org পর্যন্ত একটি চিঠির পুরো পথ
  • DNS-এর MX record আর তার priority, SMTP-র পুরো কথোপকথন, reply code-এর শ্রেণি, retry queue, bounce আর dot-stuffing
  • Port 25, 587 আর 465-এর পার্থক্য, STARTTLS আর AUTH, envelope বনাম header, আর Received header পড়ে চিঠির পথ বের করা
  • MIME, base64, quoted-printable আর বাংলা subject-এর encoded-word; POP3 বনাম IMAP, webmail আর API
  • SPF, DKIM, DMARC নিজে হিসাব করে যাচাই, সাথে ARC, MTA-STS, DANE, end-to-end encryption, spam filter আর বড় প্রেরকদের নতুন নিয়ম

১ · ইমেইল ব্যবস্থার অংশগুলো — ডাকঘরের মতো ভাগ করা কাজ

আগের কয়েকটি পর্বে আপনি দেখেছেন application layer-এর protocol কীভাবে নকশা হয় (পর্ব ৩৪), DNS কীভাবে নামকে ঠিকানায় বদলায় (পর্ব ৩৫), আর HTTP কীভাবে ব্রাউজারকে সার্ভারের সাথে কথা বলায় (পর্ব ৩৬)। ইমেইল এদের চেয়ে পুরোনো — ১৯৭১ সালে Ray Tomlinson ARPANET-এ প্রথম এক যন্ত্র থেকে আরেক যন্ত্রে বার্তা পাঠান আর ব্যবহারকারী ও যন্ত্রের নাম আলাদা করতে @ চিহ্ন বেছে নেন। তবু আজও ইমেইল ইন্টারনেটের সবচেয়ে বেশি ব্যবহৃত সেবাগুলোর একটি: চাকরির আবেদন, ব্যাংকের বিবরণী, OTP, অফিসের যোগাযোগ — সবই এর ওপর।

HTTP-তে ব্রাউজার সরাসরি সার্ভারের কাছে চায় আর সাথে সাথে উত্তর পায়। ইমেইল আলাদা: প্রাপক হয়তো তখন অফলাইন, ফোন বন্ধ। তাই ইমেইল চলে store-and-forward নীতিতে — চিঠি এক সার্ভার থেকে আরেক সার্ভারে যায়, প্রতিটি সার্ভার দায়িত্ব নিয়ে জমা রাখে, আর শেষে প্রাপকের mailbox-এ অপেক্ষা করে যতক্ষণ না তিনি পড়েন। পর্ব ৩৪-এর ভাষায়, পাঠানোর দিকটি push (প্রেরক ঠেলে দেয়), আর পড়ার দিকটি pull (প্রাপক টেনে আনেন)।

MUA — লেখার অ্যাপ

Mail User Agent: যে অ্যাপে আপনি চিঠি লেখেন আর পড়েন — Thunderbird, Outlook, ফোনের Mail অ্যাপ, বা ব্রাউজারের webmail.

চিঠি লেখা ও পড়া

MSA — জমা নেওয়ার কাউন্টার

Mail Submission Agent: নিজের প্রতিষ্ঠানের সার্ভার, যে পাসওয়ার্ড যাচাই করে আপনার চিঠি গ্রহণ করে (সাধারণত port 587).

পরিচয় দিয়ে জমা

MTA — চিঠি বহনকারী

Mail Transfer Agent: সার্ভার থেকে সার্ভারে SMTP দিয়ে চিঠি পৌঁছায় (port 25) — Postfix, Exim, Microsoft Exchange এর উদাহরণ।

সার্ভার → সার্ভার

MDA ও mailbox

Mail Delivery Agent চিঠিটি প্রাপকের mailbox-এ রাখে, দরকার হলে নিয়ম মেনে ফোল্ডারে সাজায়। পরে IMAP বা POP3 সার্ভার সেখান থেকে পড়তে দেয়।

শেষ ঠিকানা

পুরোনো দিনের ডাকঘরের কথা ভাবুন। আপনি ঘরে বসে চিঠি লিখলেন (MUA). পাড়ার পোস্ট অফিসের কাউন্টারে গিয়ে জমা দিলেন — কাউন্টারের লোক দেখলেন আপনি টিকিট লাগিয়েছেন কি না (MSA, যেখানে পরিচয় যাচাই হয়)। তারপর চিঠি জেলা সর্টিং অফিস হয়ে ডাকগাড়িতে প্রাপকের এলাকার পোস্ট অফিসে গেল (MTA থেকে MTA). কোন পোস্ট অফিসে পাঠাতে হবে, তা ঠিক হয় ঠিকানার শেষ অংশ — জেলা আর পোস্টকোড — দেখে; ইমেইলে এই কাজ করে @-এর পরের ডোমেইন আর DNS-এর MX record. প্রাপকের পোস্ট অফিস চিঠি তাঁর পোস্ট বক্সে রাখে (MDA, mailbox). প্রাপক সুবিধামতো সময়ে গিয়ে বক্স খুলে চিঠি নেন (IMAP বা POP3).

একটি চিঠির যাত্রা — alice@example.com থেকে bob@example.org

Alice-এর প্রতিষ্ঠানের ডোমেইন example.com, Bob-এর example.org. Alice ল্যাপটপে লিখে “Send” চাপলেন, আর Bob পরে ফোনে পড়লেন। মাঝখানে কী কী ঘটে, ধাপে ধাপে দেখুন। (সব নাম আর ঠিকানা উদাহরণ; IP ঠিকানাগুলো documentation-এর জন্য সংরক্ষিত পরিসর থেকে নেওয়া।)

  1. Alice-এর MUAThunderbirdলেখা
  2. MSAsmtp.example.com:587জমা
  3. DNSMX example.orgকোথায় যাবে
  4. প্রাপকের MXmx1.example.org:25SMTP relay
  5. MDA → mailboxbob/INBOXজমা রাখা
  6. Bob-এর ফোনIMAP :993পড়া
এই ধাপে কী ঘটছে
কে কার সাথে
Protocol ও port
মূল কাজ
Header-এ নতুন যা যোগ হলো
  1. লেখা। Alice নিজের MUA-তে প্রাপক, বিষয় আর লেখা দিলেন। এখনো কিছু নেটওয়ার্কে যায়নি। MUA বার্তাটিকে RFC 5322-এর নিয়মে সাজায়: ওপরে header-এর সারি, একটি ফাঁকা লাইন, তারপর body.
  2. জমা দেওয়া (submission). MUA নিজের প্রতিষ্ঠানের সার্ভার smtp.example.com-এর port 587-এ TCP সংযোগ খোলে, STARTTLS দিয়ে এনক্রিপশন চালু করে, তারপর AUTH দিয়ে Alice-এর পাসওয়ার্ড বা token দেখায়। MSA এখন দায়িত্ব নিল। সে Date আর Message-ID না থাকলে বসায়, আর প্রতিষ্ঠানের গোপন key দিয়ে DKIM সই করে (অনেক জায়গায় এই সই বাইরে যাওয়ার MTA দেয়)।
  3. MX খোঁজা। বাইরে পাঠানোর MTA দেখে প্রাপকের ডোমেইন example.org. সে DNS-এ জিজ্ঞেস করে “example.org-এর MX কী?” উত্তরে দুটি সার্ভার: preference 10-এ mx1, 20-এ mx2. ছোট সংখ্যা মানে বেশি পছন্দের, তাই প্রথমে mx1. এরপর mx1.example.org-এর IP জানতে A (বা AAAA) record খোঁজা হয় — 198.51.100.25.
  4. Relay: সার্ভার থেকে সার্ভার। mail.example.com এখন mx1.example.org-এর port 25-এ SMTP কথোপকথন চালায় (পরের অংশে পুরোটা দেখবেন)। mx1 গ্রহণের আগে পরীক্ষা করে: পাঠানো IP-টি example.com-এর SPF-এ আছে কি না, DKIM সই ঠিক কি না, DMARC নীতি কী, আর spam-এর লক্ষণ। সব ঠিক থাকলে উত্তর দেয় 250 OK. এই মুহূর্ত থেকে চিঠির দায়িত্ব mx1-এর।
  5. Mailbox-এ রাখা। MDA বার্তার ওপরে Return-Path: header বসায় (envelope-এর MAIL FROM থেকে) আর Bob-এর INBOX-এ লেখে। Bob-এর কোনো নিয়ম থাকলে (যেমন “অফিসের চিঠি ‘কাজ’ ফোল্ডারে”) এখানেই প্রয়োগ হয়। এখন চিঠিটি নিশ্চলভাবে অপেক্ষা করছে — Bob অফলাইন হলেও কিছু হারায় না।
  6. পড়া (pull). Bob-এর ফোনের Mail অ্যাপ imap.example.org-এর port 993-এ TLS সংযোগ খুলে লগইন করে, INBOX-এ নতুন বার্তা আছে কি না দেখে, আর নামিয়ে দেখায়। IMAP-এ বার্তাটি সার্ভারেই থাকে, শুধু “পড়া হয়েছে” (\Seen) চিহ্ন বসে — তাই Bob ল্যাপটপে খুললেও একই অবস্থা দেখবেন।

লক্ষ করুন, SMTP শুধু পাঠানোর protocol: MUA থেকে MSA, আর MTA থেকে MTA. পড়ার কাজে SMTP নেই — সেখানে IMAP বা POP3, বা webmail হলে HTTP. পরীক্ষায় এই ভাগটিই সবচেয়ে বেশি জিজ্ঞেস করা হয়।

২ · MX record — চিঠি কোন সার্ভারে যাবে

পর্ব ৩৫-এ DNS-এর record-এর ধরনগুলো দেখেছেন; সেখানে MX record আর TXT record-এর পরিচয়ও পেয়েছেন। ইমেইলে এই দুটিই মূল চরিত্র: MX বলে চিঠি কোথায় যাবে, আর TXT-এ থাকে SPF, DKIM, DMARC-এর নীতি — যা দিয়ে প্রাপক যাচাই করে চিঠি কে পাঠাতে পারে (অংশ ৭)।

একটি ডোমেইনের MX record দেখতে এমন (DNS zone ফাইলের চেনা লেখায়):

example.org.        3600  IN  MX  10 mx1.example.org.
example.org.        3600  IN  MX  20 mx2.example.org.
mx1.example.org.    3600  IN  A   198.51.100.25
mx2.example.org.    3600  IN  A   203.0.113.25
  • Preference (priority) সংখ্যা: ছোট সংখ্যা আগে চেষ্টা হয়। mx1 (১০) না পাওয়া গেলে mx2 (২০). একই সংখ্যার একাধিক MX থাকলে প্রেরক এলোমেলোভাবে বেছে নেয় — এভাবে load ভাগ হয়।
  • MX-এর লক্ষ্য একটি নাম, IP নয়: তারপর সেই নামের A/AAAA খুঁজতে হয়। নিয়ম অনুযায়ী MX-কে CNAME-এ নির্দেশ করা উচিত নয়।
  • MX না থাকলে: RFC 5321 অনুযায়ী প্রেরক ডোমেইনটির নিজের A/AAAA ঠিকানাকেই mail server ধরে নেয় (implicit MX). যে ডোমেইন ইমেইল একেবারেই গ্রহণ করে না, সে null MX (MX 0 ., RFC 7505) দিয়ে সেটা স্পষ্ট জানাতে পারে — তখন প্রেরক সাথে সাথে bounce দেয়, অহেতুক চেষ্টা করে না।

Linux-এ নিজে দেখতে dig MX example.org +short; Windows-এ nslookup -type=mx example.org. অনুশীলনের জন্য নিজের প্রতিষ্ঠানের ডোমেইন দেখুন।

Bounce কোথায় যায়: চিঠি পৌঁছানো না গেলে যে ফেরত-বার্তা আসে, তার নাম bounce বা NDR (Non-Delivery Report). এটি যায় envelope-এর MAIL FROM ঠিকানায়, চিঠির From: header-এ নয় — কারণটি অংশ ৪-এ পরিষ্কার হবে। Bounce পাঠানোর সময় MTA নিজে MAIL FROM:<> (খালি ঠিকানা) ব্যবহার করে, যাতে bounce-এর bounce হয়ে অসীম চক্র না বাঁধে।

৩ · SMTP — লেখায় লেখায় একটি কথোপকথন

SMTP (Simple Mail Transfer Protocol)-এর প্রথম মান RFC 821, প্রকাশ হয় ১৯৮২ সালের আগস্টে, Jon Postel-এর লেখা; একই মাসে বার্তার গঠন নিয়ে RFC 822. পরে RFC 2821 (২০০১) হয়ে আজকের মূল মান RFC 5321 (২০০৮)। মাঝখানে ১৯৯৫ সালে (RFC 1869) এসেছিল ESMTP — সার্ভার নিজের বাড়তি ক্ষমতা ঘোষণা করতে পারে, আর ক্লায়েন্ট পুরোনো HELO-র বদলে EHLO দিয়ে শুরু করে।

SMTP চলে TCP-এর ওপর (পর্ব ২৯), আর পুরো কথোপকথন মানুষের পড়ার মতো লেখায় — প্রতিটি লাইন শেষ হয় CRLF দিয়ে। ক্লায়েন্ট একটি command পাঠায় (চার অক্ষরের শব্দ: EHLO, MAIL, RCPT, DATA, QUIT…), সার্ভার একটি তিন অঙ্কের reply code আর ব্যাখ্যা দিয়ে উত্তর দেয়। এটি একটি state machine: ভুল ক্রমে command দিলে (যেমন MAIL-এর আগে RCPT) সার্ভার 503 bad sequence of commands বলে।

নিচে mail.example.com (ক্লায়েন্ট, C) আর mx1.example.org (সার্ভার, S)-এর একটি পূর্ণ কথোপকথন — সরলতার জন্য STARTTLS-এর অংশ বাদ রাখা হয়েছে। Bob আছেন, carol নামে কেউ নেই।

mail.example.com (C) ↔ mx1.example.org (S), TCP port 25
তারে যা গেল
Server-এর অবস্থা
Envelope
  1. সার্ভার আগে কথা বলে। TCP সংযোগ হওয়ামাত্র সার্ভার 220 দিয়ে নিজের নাম জানায়। HTTP-তে যেমন ক্লায়েন্ট আগে অনুরোধ পাঠায়, SMTP-তে উল্টো — ক্লায়েন্ট অভিবাদনের অপেক্ষা করে।
  2. EHLO আর ক্ষমতার তালিকা। ক্লায়েন্ট নিজের নাম বলে। সার্ভার কয়েক লাইনের 250 দেয় — শেষ লাইন ছাড়া সবগুলোতে কোডের পরে -, শেষটিতে ফাঁকা জায়গা; এভাবেই ক্লায়েন্ট বোঝে উত্তর শেষ। SIZE মানে সর্বোচ্চ বার্তার আকার (এখানে প্রায় ৩৪ MiB), 8BITMIME মানে ৮-bit লেখা চলবে, STARTTLS মানে এনক্রিপশনে যাওয়া যাবে। বাস্তবে ক্লায়েন্ট এখানে STARTTLS দেয়, TLS handshake হয়, তারপর আবার EHLO.
  3. MAIL FROM — খামের উল্টো পিঠের ঠিকানা। এটি envelope-এর প্রেরক, যাকে reverse-path-ও বলে — সমস্যা হলে bounce এখানেই যাবে। 250 মানে গৃহীত। 2.1.0 অংশটি enhanced status code (RFC 3463) — যন্ত্রের পড়ার জন্য আরও সূক্ষ্ম কারণ।
  4. RCPT TO — প্রথম প্রাপক। প্রতিটি প্রাপকের জন্য আলাদা RCPT TO, আর প্রতিটির আলাদা উত্তর। bob আছে, তাই 250.
  5. দ্বিতীয় প্রাপক — স্থায়ী ব্যর্থতা। carol নেই: 550 5.1.1. শুরুর ৫ মানে স্থায়ী — আবার চেষ্টা করে লাভ নেই। পুরো লেনদেন ভাঙে না; bob-এর জন্য চিঠি যাবে, আর পাঠানো সার্ভার Alice-কে carol-এর ব্যাপারে bounce পাঠাবে।
  6. DATA আর 354. ক্লায়েন্ট বলে “এবার চিঠি দিচ্ছি”। সার্ভার 354 দিয়ে জানায় কীভাবে শেষ করতে হবে: একটি লাইনে শুধু একটি বিন্দু। ৩ দিয়ে শুরু মানে “ঠিক আছে, আরও কিছু পাঠান”।
  7. বার্তার লাইন আর dot-stuffing. ওপরে header (From:, To:, Subject:), একটি ফাঁকা লাইন, তারপর body. Body-র একটি লাইন আসলে “.net is the folder name” — বিন্দু দিয়ে শুরু। একা বিন্দু শেষের সংকেত, তাই বিভ্রান্তি এড়াতে ক্লায়েন্ট শুরুর বিন্দুর সামনে আরেকটি বিন্দু বসিয়েছে: “..net”. এর নাম dot-stuffing. এই ধাপে সার্ভার কোনো উত্তর দেয় না।
  8. একক বিন্দু: বার্তা শেষ। সার্ভার প্রতিটি লাইনের শুরুর একটি বাড়তি বিন্দু মুছে আসল লেখা ফিরিয়ে আনে (“.net…”), বার্তা নিজের queue-তে রাখে, আর 250 … queued as 4F2A1C বলে। এই 250-ই দায়িত্বের হস্তান্তর: এখন থেকে চিঠি হারালে দায় mx1-এর।
  9. বিদায়। QUIT-এর উত্তরে 221, তারপর TCP সংযোগ বন্ধ (পর্ব ২৯-এর FIN বিনিময়)। একই সংযোগে QUIT-এর আগে আরও MAIL FROM দিয়ে একাধিক চিঠিও পাঠানো যায়।

Reply code-এর চার শ্রেণি

প্রথম অঙ্কঅর্থউদাহরণপ্রেরকের করণীয়
2xxসফল220 প্রস্তুত, 250 ঠিক আছে, 221 বিদায়পরের ধাপ
3xxমধ্যবর্তী — আরও তথ্য দিন354 বার্তা পাঠান, 334 AUTH-এর পরের অংশচাওয়া জিনিস পাঠানো
4xxসাময়িক ব্যর্থতা421 সেবা এখন বন্ধ, 450/451 এখন নয়, 452 জায়গা কমqueue-তে রেখে পরে আবার চেষ্টা
5xxস্থায়ী ব্যর্থতা550 mailbox নেই বা নীতিগত প্রত্যাখ্যান, 552 আকার বেশি, 554 লেনদেন ব্যর্থআর চেষ্টা নয় — প্রেরককে bounce (NDR)

সাময়িক আর স্থায়ী ব্যর্থতার পার্থক্যই ইমেইলকে নির্ভরযোগ্য করে: 4xx পেলে পাঠানো MTA চিঠিটি নিজের mail queue-তে রেখে দেয় আর কিছুক্ষণ পরপর আবার চেষ্টা করে। RFC 5321 পরামর্শ দেয় দুই চেষ্টার মাঝে অন্তত ৩০ মিনিট রাখতে আর অন্তত ৪–৫ দিন চেষ্টা চালিয়ে যেতে; বাস্তব সার্ভারগুলো নিজের মতো সময়সূচি রাখে (যেমন Postfix-এর ডিফল্ট সর্বোচ্চ ৫ দিন)। শেষ পর্যন্ত না গেলে প্রেরক bounce পান। অনেক সার্ভার অচেনা প্রেরককে প্রথমবার ইচ্ছা করে 4xx দেয় — greylisting — কারণ সত্যিকারের MTA আবার চেষ্টা করে, কিন্তু অনেক spam পাঠানোর সফটওয়্যার করে না।

নিচের simulator-এ একটি ছোট MX সার্ভার state machine হিসেবে লেখা। প্রথম চেষ্টায় bob greylist-এ পড়ে 451 পায়, carol নেই বলে 550; ৩০ মিনিট পরের চেষ্টায় bob-এর চিঠি যায়, আর body-র একটি বিন্দু-দিয়ে-শুরু লাইন dot-stuffing হয়।

// Toy SMTP: sending MTA (C) talks to example.org's MX (S). Try 1: bob greylisted, carol unknown.
function mx(greylist) {
  let st = "new", rcpt = [], body = [];
  return (line) => {
    if (st === "data") {                                    // body lines get no reply
      if (line === ".") { st = "ready"; return `250 2.0.0 queued for ${rcpt}`; }
      body.push(line.startsWith(".") ? line.slice(1) : line); return null; }  // un-stuff
    const cmd = line.slice(0, 4);
    if (cmd === "EHLO") { st = "ready"; return "250-mx.example.org\n   250 STARTTLS"; }
    if (cmd === "MAIL" && st === "ready") { st = "mail"; return "250 2.1.0 sender ok"; }
    if (cmd === "RCPT" && st === "mail") {
      if (!line.includes("<bob@")) return "550 5.1.1 no such user here";
      if (greylist) return "451 4.7.1 greylisted, try again later";
      rcpt.push("bob"); return "250 2.1.5 recipient ok";
    }
    if (cmd === "DATA" && rcpt.length) { st = "data"; return "354 end data with <CRLF>.<CRLF>"; }
    if (cmd === "QUIT") return `221 2.0.0 bye   (server stored: ${JSON.stringify(body)})`;
    return "503 5.5.1 bad sequence of commands";
  };
}
const body = ["Subject: test", "", "Hi Bob,", ".hidden starts with a dot", "-- Alice"];
const stuffed = body.map(l => (l.startsWith(".") ? "." + l : l));   // dot-stuffing
let queue = ["bob", "carol"];
const why = { 4: "4xx temporary: keep in queue, retry later", 5: "5xx permanent: drop, bounce (NDR) to alice" };
for (const [t, grey] of [[0, true], [30, false]]) {
  console.log(`=== attempt at t=${t} min, queue: ${queue}`);
  const S = mx(grey), say = (l) => { console.log("C: " + l); const r = S(l); if (r) console.log("S: " + r); return r || ""; };
  console.log("S: 220 mx.example.org ESMTP"); say("EHLO mail.example.com"); say("MAIL FROM:<alice@example.com>");
  const ok = queue.filter(u => {
    const c = say(`RCPT TO:<${u}@example.org>`)[0];
    if (why[c]) console.log(`   [${u}: ${why[c]}]`); if (c === "5") queue = queue.filter(x => x !== u);
    return c === "2";
  });
  if (ok.length) { say("DATA"); stuffed.forEach(say); say("."); queue = []; }  say("QUIT");
}

আউটপুট:

=== attempt at t=0 min, queue: bob,carol
S: 220 mx.example.org ESMTP
C: EHLO mail.example.com
S: 250-mx.example.org
   250 STARTTLS
C: MAIL FROM:<alice@example.com>
S: 250 2.1.0 sender ok
C: RCPT TO:<bob@example.org>
S: 451 4.7.1 greylisted, try again later
   [bob: 4xx temporary: keep in queue, retry later]
C: RCPT TO:<carol@example.org>
S: 550 5.1.1 no such user here
   [carol: 5xx permanent: drop, bounce (NDR) to alice]
C: QUIT
S: 221 2.0.0 bye   (server stored: [])
=== attempt at t=30 min, queue: bob
S: 220 mx.example.org ESMTP
C: EHLO mail.example.com
S: 250-mx.example.org
   250 STARTTLS
C: MAIL FROM:<alice@example.com>
S: 250 2.1.0 sender ok
C: RCPT TO:<bob@example.org>
S: 250 2.1.5 recipient ok
C: DATA
S: 354 end data with <CRLF>.<CRLF>
C: Subject: test
C: 
C: Hi Bob,
C: ..hidden starts with a dot
C: -- Alice
C: .
S: 250 2.0.0 queued for bob
C: QUIT
S: 221 2.0.0 bye   (server stored: ["Subject: test","","Hi Bob,",".hidden starts with a dot","-- Alice"])

প্রথম চেষ্টায় (t=0) bob-এর উত্তর 451 4.7.1 — ৪ দিয়ে শুরু, তাই ক্লায়েন্ট তাকে queue-তে রাখল। carol-এর উত্তর 550 5.1.1 — স্থায়ী, তাই তাকে queue থেকে বাদ দিয়ে Alice-কে bounce. কোনো প্রাপক গৃহীত না হওয়ায় ক্লায়েন্ট DATA না পাঠিয়ে সরাসরি QUIT করল (সার্ভারে কিছু জমা নেই: [])। দ্বিতীয় চেষ্টায় queue-তে শুধু bob; এবার 250, তারপর 354. তারে যাওয়া লাইন ..hidden starts with a dot — শুরুতে দুটি বিন্দু; কিন্তু শেষ লাইনে সার্ভারের জমা করা লেখায় আবার একটি বিন্দু: ".hidden starts with a dot". অর্থাৎ dot-stuffing পুরোপুরি স্বচ্ছ — প্রাপক ঠিক তা-ই পান যা প্রেরক লিখেছিলেন। লক্ষ করুন, body-র লাইনগুলোর (C:) পরে কোনো S: নেই; একক .-এর পরেই 250 2.0.0 queued for bob.

মূল ধারণা

Dot-stuffing হলো পর্ব ১০-এর byte stuffing-এরই লেখা-ভিত্তিক রূপ: যে চিহ্ন “শেষ” বোঝায়, ডেটার ভেতরে সেটি এলে তার আগে একটি পালানোর চিহ্ন বসানো হয়, আর প্রাপক তা মুছে দেয়। একই সমস্যা, একই সমাধান — শুধু স্তর আলাদা।

৪ · Port 25, 587, 465 — আর খাম বনাম চিঠি

Portকাজএনক্রিপশনকে ব্যবহার করে
25MTA থেকে MTA relayসাধারণ লেখায় শুরু, সম্ভব হলে STARTTLS (RFC 3207)সার্ভার ↔ সার্ভার; সাধারণত পাসওয়ার্ড লাগে না
587Submission (RFC 6409)STARTTLS, তারপর বাধ্যতামূলক AUTHMUA → MSA
465SubmissionImplicit TLS — প্রথম বাইট থেকেই TLSMUA → MSA (RFC 8314-এর সুপারিশ)

Port 465-এর ইতিহাস জটিল: ১৯৯০-এর দশকের শেষে অল্প সময়ের জন্য “SMTP over SSL”-এর জন্য নিবন্ধিত হয়ে পরে তুলে নেওয়া হয়, তবু অনেক সফটওয়্যার এটি ব্যবহার করে যাচ্ছিল। ২০১৮ সালে RFC 8314 submission-এর জন্য implicit TLS-কেই পছন্দনীয় বলে, কারণ STARTTLS-এ শুরুর অংশ এনক্রিপ্ট-হীন থাকে (অংশ ৮)। আজ ৫৮৭ আর ৪৬৫ দুটোই প্রচলিত।

বাসার সংযোগ থেকে port 25 কেন বন্ধ

অনেক ISP বাসা বা মোবাইল সংযোগ থেকে বাইরের port 25 আটকে রাখে, কারণ ক্ষতিকর সফটওয়্যারে আক্রান্ত কম্পিউটার (botnet) সরাসরি অন্যের MX-এ লাখো spam পাঠাতে পারে। সাধারণ ব্যবহারকারীর এই port লাগেই না — তাঁর অ্যাপ MSA-তে ৫৮৭ বা ৪৬৫ দিয়ে পাঠায়, আর MSA-ই বাইরে relay করে। নিজের মেইল সার্ভার চালাতে চাইলে সমাধান ISP-র অনুমতি বা একটি relay সেবা — firewall ঘুরিয়ে যাওয়ার চেষ্টা নয়। (নীতি ISP-ভেদে ভিন্ন, আর সময়ের সাথে বদলায়।)

Envelope বনাম header — খামের ঠিকানা আর চিঠির “প্রিয় …”

অংশ ৩-এর কথোপকথনে প্রেরক-প্রাপক দুবার এসেছে: একবার MAIL FROM/RCPT TO-তে, আবার DATA-র ভেতরে From:/To: header-এ। প্রথমটি envelope — MTA শুধু এটি দেখে চিঠি পৌঁছায়। দ্বিতীয়টি চিঠির ভেতরের লেখা — MUA পাঠককে দেখায়, কিন্তু পৌঁছানোয় এর কোনো ভূমিকা নেই। ডাকঘরের ভাষায়: পিয়ন খামের ওপরের ঠিকানা পড়েন; ভেতরে কেউ “ইতি, আপনার ব্যাংক ম্যানেজার” লিখলে পিয়ন তা যাচাই করেন না।

  • BCC: Alice Bcc-তে dana@example.net দিলেন। MUA বা MSA dana-কে envelope-এ একটি বাড়তি RCPT TO হিসেবে রাখে, কিন্তু পাঠানোর আগে Bcc: header মুছে দেয়। ফলে dana চিঠি পান, অথচ To:/Cc:-এর কেউ জানেন না।
  • Mailing list ও forwarding: একটি তালিকার ঠিকানায় পাঠানো চিঠির To:-এ থাকে তালিকার নাম, কিন্তু envelope-এ প্রতিটি সদস্যের ঠিকানা; আর bounce যাতে তালিকা-পরিচালকের কাছে যায়, সেজন্য MAIL FROM বদলানো হয়।
  • Spoofing: SMTP নিজে কোনো header যাচাই করে না। কেউ নিজের সার্ভার থেকে From: security@example.com লিখে পাঠাতে পারে, যদিও সে example.com-এর কেউ নয় — email spoofing. অংশ ৭-এর SPF, DKIM, DMARC ঠিক এই ফাঁক বন্ধ করতে এসেছে।

Open relay — যে ভুল ইন্টারনেটকে spam-এ ভরিয়েছিল: যে MTA যে কারও কাছ থেকে যে কারও জন্য চিঠি নিয়ে বাইরে relay করে, তাকে open relay বলে। ১৯৮০-র দশকে এটিই স্বাভাবিক ছিল — নেটওয়ার্কের সবাই সবাইকে চিনত। ১৯৯০-এর দশকে spammer-রা এমন সার্ভার খুঁজে নিয়ে নিজেদের চিঠি অন্যের নামে পাঠাতে শুরু করে। আজকের নিয়ম: port 25-এ সার্ভার শুধু নিজের ডোমেইনের প্রাপকের চিঠি নেবে, আর বাইরে relay করবে কেবল পাসওয়ার্ড-যাচাই করা নিজস্ব ব্যবহারকারী বা নিজের নেটওয়ার্কের জন্য। নিজের সার্ভার open relay কি না, তা পরীক্ষা করুন শুধু নিজের সার্ভারে, নিজের অনুমতিতে।

৫ · বার্তার গঠন — RFC 5322 header, Received আর MIME

DATA-র ভেতরে যা যায়, তার নিয়ম RFC 5322 (আগে RFC 822, RFC 2822): ওপরে header-এর সারি — প্রতিটি নাম: মান — তারপর একটি ফাঁকা লাইন, তারপর body. মূল header-গুলো:

Headerকাজকে বসায়
From:লেখক — পাঠক এটাই দেখেন; বাধ্যতামূলকMUA
To:, Cc:প্রকাশ্য প্রাপক (Bcc পাঠানোর আগে মুছে যায়)MUA
Subject:বিষয়MUA
Date:লেখার সময়, সময়-অঞ্চলসহ; বাধ্যতামূলকMUA বা MSA
Message-ID:বিশ্বজুড়ে অনন্য পরিচয়, যেমন <20261026.4f2a@example.com>; উত্তরের In-Reply-To: এটি দিয়ে thread বানায়MUA বা MSA
Received:প্রতিটি MTA-র “এখান দিয়ে গেছে” সিলপ্রতিটি MTA, ওপরে যোগ করে
Return-Path:envelope-এর MAIL FROM-এর কপিশেষ বিতরণের সময় MDA

Received header — নিচ থেকে ওপরে পড়ুন

প্রতিটি MTA চিঠি নেওয়ার সময় একটি নতুন Received লাইন সবার ওপরে বসায়। তাই সবচেয়ে নিচেরটি প্রথম ধাপ, সবচেয়ে ওপরেরটি শেষ ধাপ। কুরিয়ারের ট্র্যাকিং ইতিহাসের মতো — শুধু উল্টো ক্রমে লেখা। Bob-এর কাছে পৌঁছানো চিঠির ওপরের অংশ (উদাহরণ):

Return-Path: <alice@example.com>
Received: from mail.example.com (mail.example.com [192.0.2.25])
        by mx1.example.org with ESMTPS id 4F2A1C
        for <bob@example.org>; Mon, 26 Oct 2026 10:15:09 +0600
Received: from [10.0.2.15] (unknown [192.0.2.140])
        by smtp.example.com with ESMTPSA id 77B0E2
        for <bob@example.org>; Mon, 26 Oct 2026 10:15:07 +0600
Authentication-Results: mx1.example.org; spf=pass smtp.mailfrom=example.com;
        dkim=pass header.d=example.com; dmarc=pass header.from=example.com
From: Alice <alice@example.com>
To: Bob <bob@example.org>

নিচ থেকে পড়লে: Alice-এর ল্যাপটপ (অফিসের ভেতরের ঠিকানা 10.0.2.15, বাইরে দেখা গেছে 192.0.2.140) MSA smtp.example.com-এ জমা দিল — ESMTPSA-র S মানে TLS, A মানে AUTH. দুই সেকেন্ড পরে mail.example.com থেকে mx1.example.org-এ গেল TLS-সহ। সাবধানতা: প্রতিটি Received শুধু সেই সার্ভারের দাবি; নিজের সার্ভারের লাইন ভরসাযোগ্য, কিন্তু নিচের লাইন প্রেরক বানিয়ে লিখতে পারে।

MIME — ৭-bit ASCII-র পৃথিবীতে বাংলা আর ফাইল

RFC 822-এর ইমেইল ছিল শুধু ৭-bit ASCII লেখা, লাইন ১০০০ অক্ষরের কম। বাংলা, ছবি বা PDF পাঠানোর উপায় ছিল না। ১৯৯২ সালে প্রথম, আর ১৯৯৬ সালে RFC 2045–2049-এ চূড়ান্ত হয় MIME (Multipurpose Internet Mail Extensions). মূল কৌশল: SMTP না বদলে, বার্তার ভেতরে কিছু নতুন header যোগ করে যেকোনো ডেটাকে ASCII লেখায় মুড়ে দেওয়া।

  • MIME-Version: 1.0 — “এটি MIME বার্তা”।
  • Content-Type: — কী ধরনের জিনিস: text/plain; charset=UTF-8, text/html, image/png, application/pdf.
  • multipart/alternative — একই লেখার একাধিক রূপ (সাধারণ লেখা আর HTML); MUA যেটা ভালো দেখাতে পারে সেটা দেখায়।
  • multipart/mixed — আলাদা আলাদা অংশ: লেখা আর সংযুক্ত ফাইল। অংশগুলো আলাদা হয় একটি boundary লাইন দিয়ে: --boundary প্রতিটি অংশের আগে, আর শেষে --boundary--. Boundary এমন হতে হবে যা কোনো অংশের ভেতরে নেই।
  • Content-Transfer-Encoding: — ডেটাকে কীভাবে ASCII বানানো হলো: base64 বা quoted-printable (৮-bit সমর্থিত হলে 8bit-ও চলে)।

Base64 — হাতে হিসাব

নিয়ম: ৩ বাইট = ২৪ bit; সেটিকে ৬ bit করে ৪ টুকরো; প্রতিটি টুকরো (০–৬৩) একটি অক্ষরে — A–Z (০–২৫), a–z (২৬–৫১), 0–9 (৫২–৬১), + (৬২), / (৬৩)। শেষে বাইট কম পড়লে = দিয়ে পূরণ। উদাহরণ “Hi!”:

H        i        !
01001000 01101001 00100001          ← ৩ বাইট = ২৪ bit
010010 000110 100100 100001          ← ৬ bit করে ৪ টুকরো
  18      6      36     33
   S      G       k      h           → "SGkh"

১৮ = S (A থেকে ১৮তম), ৬ = G, ৩৬ = ৩৬ − ২৬ = ১০ → k, ৩৩ = ৩৩ − ২৬ = ৭ → h. ফলে আকার বাড়ে ৪/৩ গুণ, প্রায় ৩৩%, আর MIME প্রতি ৭৬ অক্ষরে লাইন ভাঙে — তাই ১০ MB-র ফাইল তারে প্রায় ১৩.৭ MB হয়ে যায়। এজন্য মেইল সরবরাহকারীর “২৫ MB সংযুক্তির সীমা” আসলে মূল ফাইলের প্রায় ১৮–১৯ MB.

Quoted-printable প্রায় পুরোটা ASCII লেখার জন্য ভালো: সাধারণ অক্ষর যেমন আছে তেমন, শুধু অন্য বাইট =XX (হেক্স) আকারে। “café” হয় caf=C3=A9 (é-র UTF-8 বাইট C3 A9), আর লম্বা লাইনের শেষে = মানে “নরম লাইন-ভাঙা”। বাংলার প্রতিটি অক্ষর UTF-8-এ ৩ বাইট, তাই quoted-printable-এ একটি বাংলা অক্ষর ৯টি ASCII অক্ষর হয়ে যায় — বাংলার জন্য base64 অনেক সাশ্রয়ী।

Header-এ বাংলা: encoded-word

Header-এর ভেতরে Content-Transfer-Encoding দেওয়া যায় না, তাই RFC 2047 আনে encoded-word: =?charset?B?base64?= (B = base64) বা =?charset?Q?…?= (Q = quoted-printable-এর মতো)। একটি encoded-word ৭৫ অক্ষরের বেশি হতে পারে না; লম্বা subject কয়েকটি word-এ ভাঙে। (নতুন SMTPUTF8 এক্সটেনশন, RFC 6531, দুই সার্ভার সমর্থন করলে header আর ঠিকানায় সরাসরি UTF-8 পাঠাতে দেয় — তবে encoded-word এখনো সর্বত্র চলে।)

নিচের কোড একটি বাংলা subject-কে encoded-word বানায়, একটি ছোট CSV ফাইলকে base64-এ মোড়ে, পুরো multipart/mixed বার্তা তৈরি করে, তারপর প্রাপকের মতো খুলে আবার আসল লেখা বের করে।

// MIME by hand: Bangla subject as an RFC 2047 encoded-word, a base64 attachment, multipart/mixed.
const enc = new TextEncoder(), dec = new TextDecoder();
const b64 = (bytes) => btoa(String.fromCharCode(...bytes));            // bytes -> base64 text
const unb64 = (s) => Uint8Array.from(atob(s), (c) => c.charCodeAt(0));  // base64 text -> bytes
const wrap = (s) => s.match(/.{1,76}/g).join("\r\n");                     // MIME: lines of max 76

const hi = enc.encode("Hi!");                                              // the worked example
console.log("Hi! =", [...hi].map((b) => b.toString(2).padStart(8, "0")).join(" "), "->", b64(hi));
const subj = enc.encode("ঢাকা অফিস");
const word = `=?UTF-8?B?${b64(subj)}?=`;
console.log(`subject: ${subj.length} UTF-8 bytes -> ${word}`);

const csv = enc.encode("roll,name,marks\n1,Rahim,78\n2,Karim,85\n3,Salma,91\n4,Nodi,88\n");
const B = "b39-7f3a";                        // boundary: must never appear inside any part
const msg = ["From: alice@example.com", "To: bob@example.org", `Subject: ${word}`,
  "MIME-Version: 1.0", `Content-Type: multipart/mixed; boundary="${B}"`, "",
  `--${B}`, "Content-Type: text/plain; charset=UTF-8", "Content-Transfer-Encoding: base64", "",
  wrap(b64(enc.encode("ফাইল সংযুক্ত"))),
  `--${B}`, 'Content-Type: text/csv; name="marks.csv"', "Content-Transfer-Encoding: base64",
  'Content-Disposition: attachment; filename="marks.csv"', "", wrap(b64(csv)), `--${B}--`, ""].join("\r\n");
console.log(`----- message (${csv.length}-byte file -> ${b64(csv).length} base64 chars) -----`);
console.log(msg.replace(/\r/g, ""));

console.log("----- receiver decodes -----");
const w = msg.match(/=\?UTF-8\?B\?([^?]+)\?=/)[1];
console.log("Subject:", dec.decode(unb64(w)));
for (const part of msg.split(`--${B}`).slice(1, -1)) {
  const [head, body] = part.split("\r\n\r\n");
  const type = head.match(/Content-Type: ([^;\r]+)/)[1];
  const bytes = unb64(body.replace(/\r\n/g, ""));
  console.log(`[${type}, ${bytes.length} bytes]`, JSON.stringify(dec.decode(bytes)));
}

আউটপুট:

Hi! = 01001000 01101001 00100001 -> SGkh
subject: 25 UTF-8 bytes -> =?UTF-8?B?4Kai4Ka+4KaV4Ka+IOCmheCmq+Cmv+CmuA==?=
----- message (59-byte file -> 80 base64 chars) -----
From: alice@example.com
To: bob@example.org
Subject: =?UTF-8?B?4Kai4Ka+4KaV4Ka+IOCmheCmq+Cmv+CmuA==?=
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="b39-7f3a"

--b39-7f3a
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: base64

4Kar4Ka+4KaH4KayIOCmuOCmguCmr+CngeCmleCnjeCmpA==
--b39-7f3a
Content-Type: text/csv; name="marks.csv"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="marks.csv"

cm9sbCxuYW1lLG1hcmtzCjEsUmFoaW0sNzgKMixLYXJpbSw4NQozLFNhbG1hLDkxCjQsTm9kaSw4
OAo=
--b39-7f3a--

----- receiver decodes -----
Subject: ঢাকা অফিস
[text/plain, 34 bytes] "ফাইল সংযুক্ত"
[text/csv, 59 bytes] "roll,name,marks\n1,Rahim,78\n2,Karim,85\n3,Salma,91\n4,Nodi,88\n"

প্রথম লাইনে হাতের হিসাবটাই মিলল: “Hi!” → SGkh. “ঢাকা অফিস”-এ ৮টি বাংলা code point (কার-চিহ্নসহ, প্রতিটি ৩ বাইট) আর একটি ফাঁকা জায়গা — মোট ২৫ বাইট; ২৫ = ৮ × ৩ + ১, তাই ৯টি চার-অক্ষরের দল = ৩৬ অক্ষর, শেষ দলে মাত্র এক বাইট বলে দুটি ==. শুরুর 4Kai হলো ঢ-এর তিন বাইট E0 A6 A2. বার্তায় boundary b39-7f3a: base64-এর বর্ণমালায় - নেই, তাই কোনো অংশের ভেতরে এই লাইন দৈবাৎ তৈরি হতে পারে না। ৫৯ বাইটের CSV হলো ৮০ অক্ষর (৫৯ = ১৯ × ৩ + ২ → ২০ দল, শেষে একটি =), যা ৭৬ অক্ষরে ভেঙে দ্বিতীয় লাইনে OAo=. শেষে প্রাপক boundary ধরে অংশ আলাদা করে, লাইন-ভাঙা মুছে base64 খুলে আবার ঠিক ৩৪ আর ৫৯ বাইট পেয়েছে — বাংলা লেখা আর ফাইল অক্ষত।

৬ · Push আর pull — POP3, IMAP, webmail আর একটি আসল SMTP সংযোগ

SMTP ঠেলে পাঠায়: প্রেরকের সার্ভার নিজে উদ্যোগ নিয়ে প্রাপকের সার্ভারে যায়। কিন্তু Bob-এর ফোন সার্ভার নয় — তার স্থায়ী ঠিকানা নেই, সে প্রায়ই NAT-এর পেছনে (পর্ব ১৯) বা বন্ধ। তাই শেষ ধাপটি টানা: Bob-এর অ্যাপ নিজে সার্ভারের কাছে গিয়ে জিজ্ঞেস করে “নতুন কিছু আছে?” এই কাজের দুটি প্রধান protocol:

বিষয়POP3IMAP
মানRFC 1939 (১৯৯৬)IMAP4rev1 RFC 3501 (২০০৩), IMAP4rev2 RFC 9051 (২০২১)
Port110 (STARTTLS), 995 (implicit TLS)143 (STARTTLS), 993 (implicit TLS)
মূল ধারণানামানো আর (সাধারণত) সার্ভার থেকে মুছে ফেলাবার্তা সার্ভারেই থাকে; অ্যাপ তার একটি প্রতিচ্ছবি দেখায়
ফোল্ডারশুধু একটি mailboxসার্ভারে ফোল্ডার, সরানো, কপি
পড়া/না-পড়া চিহ্নসার্ভারে থাকে নাসার্ভারে flag (\Seen, \Flagged), সব যন্ত্রে একই
একাধিক যন্ত্রঅসুবিধা — এক যন্ত্রে নামালে অন্যটিতে নেইস্বাভাবিক — ফোন, ল্যাপটপ, ব্রাউজার একই অবস্থা দেখে
আংশিক নামানোপ্রায় নেই (পুরো বার্তা)শুধু header, বা শুধু একটি MIME অংশ আনা যায়
নতুন বার্তার খবরবারবার জিজ্ঞেস (polling)IDLE দিয়ে সংযোগ খোলা রেখে সার্ভার জানায়
সার্ভারের খরচকম — সার্ভার শুধু কিছুদিন রাখেবেশি — সব বার্তা স্থায়ীভাবে, অনুসন্ধানসহ

POP3 হলো পোস্ট অফিসের বক্স থেকে চিঠি তুলে বাসায় নিয়ে আসা — বক্স খালি, চিঠি এখন আপনার আলমারিতে; অফিসে গিয়ে আর সেই চিঠি পাবেন না। IMAP হলো ব্যাংকের লকারের মতো — জিনিস ব্যাংকেই থাকে, আপনি যেকোনো শাখা থেকে গিয়ে দেখতে পারেন, ফাইলে সাজিয়ে রাখতে পারেন, আর যেখান থেকেই দেখুন একই অবস্থা।

Webmail আর API

ব্রাউজারে Gmail বা Outlook খুললে আপনার যন্ত্র আর IMAP বা SMTP বলে না — ব্রাউজার webmail সার্ভারের সাথে HTTPS-এ কথা বলে (পর্ব ৩৬-এর HTTP, আর পর্ব ৪৮-এর TLS). Webmail সার্ভার ভেতরে mailbox থেকে পড়ে, আর পাঠানোর সময় সরবরাহকারীর MTA বাইরের ডোমেইনে সাধারণ SMTP দিয়েই পাঠায়। অর্থাৎ শেষ মাইলে HTTP, সার্ভার থেকে সার্ভারে এখনো SMTP. বড় সরবরাহকারীরা নিজস্ব HTTP API-ও দেয়, আর মান হিসেবে আছে JMAP (RFC 8620, 8621; ২০১৯) — IMAP-এর কাজ JSON আর HTTP দিয়ে, মোবাইলের জন্য বেশি দক্ষভাবে। অ্যাপ থেকে বিপুল পরিমাণে চিঠি পাঠানোর সেবাগুলোও (লেনদেনের রসিদ, OTP) প্রায়ই HTTP API নেয়, কিন্তু নিজেরা বাইরে SMTP দিয়েই পৌঁছায়।

আসল TCP-তে একটি SMTP কথোপকথন

এতক্ষণ simulator দেখেছেন; এবার সত্যিকারের socket. নিচের C প্রোগ্রাম loopback (127.0.0.1) port 2525-এ একটি listening socket খোলে, তারপর fork() করে: child process একটি ছোট SMTP-ধাঁচের সার্ভার হয়, parent হয় ক্লায়েন্ট। ক্লায়েন্ট পুরো কথোপকথন পাঠায় আর প্রতিটি লাইন ছাপে; সার্ভার নিজে কিছু ছাপে না, তাই আউটপুটের ক্রম সবসময় একই। (Socket প্রোগ্রামিংয়ের বিস্তারিত পর্ব ৪১-এ; সার্ভারটি ইচ্ছা করে অতি সরল — আসল MTA নয়।)

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <arpa/inet.h>
static void mx(int ls) {                  /* child process: a tiny SMTP-like server */
    int c = accept(ls, NULL, NULL), n = 0, data = 0; char l[256], last[256] = "";
    FILE *in = fdopen(c, "r"), *out = fdopen(dup(c), "w");
    setvbuf(out, NULL, _IOLBF, 0); fputs("220 mx.example.org toy ESMTP\r\n", out);
    while (fgets(l, sizeof l, in)) { l[strcspn(l, "\r\n")] = 0;     /* strip CRLF */
        if (data && strcmp(l, ".") != 0) { n++; strcpy(last, l[0] == '.' ? l + 1 : l); }
        else if (data) { data = 0; fprintf(out, "250 OK: %d lines, last: %s\r\n", n, last); }
        else if (!strncmp(l, "RCPT TO:<carol", 14)) fputs("550 5.1.1 no such user\r\n", out);
        else if (!strncmp(l, "DATA", 4)) { data = 1; fputs("354 end with <CRLF>.<CRLF>\r\n", out); }
        else if (!strncmp(l, "QUIT", 4)) { fputs("221 bye\r\n", out); break; }
        else fputs(strncmp(l, "EHLO", 4) ? "250 OK\r\n" : "250 mx.example.org\r\n", out);
    }
}
int main(void) {
    struct sockaddr_in a = { .sin_family = AF_INET, .sin_port = htons(2525),
                             .sin_addr.s_addr = htonl(INADDR_LOOPBACK) };
    int ls = socket(AF_INET, SOCK_STREAM, 0), s = socket(AF_INET, SOCK_STREAM, 0);
    if (bind(ls, (struct sockaddr *)&a, sizeof a) || listen(ls, 1)) { perror("bind"); return 1; }
    fflush(stdout); pid_t pid = fork(); if (pid == 0) { mx(ls); _exit(0); }   /* child = server */
    if (connect(s, (struct sockaddr *)&a, sizeof a)) { perror("connect"); return 1; }
    FILE *in = fdopen(s, "r"), *out = fdopen(dup(s), "w"); char r[256];
    const char *cmd[] = { "EHLO mail.example.com", "MAIL FROM:<alice@example.com>", "RCPT TO:<bob@example.org>",
        "RCPT TO:<carol@example.org>", "DATA", "Subject: hi", "", "..starts with a dot", ".", "QUIT", NULL };
    for (int i = -1; i < 0 || cmd[i]; i++) {     /* i = -1: only read the 220 greeting */
        if (i >= 0) { fprintf(out, "%s\r\n", cmd[i]); fflush(out); printf("C: %s\n", cmd[i]); }
        if ((i < 5 || i > 7) && fgets(r, sizeof r, in)) {   /* lines 5-7 are inside DATA: no reply */
            r[strcspn(r, "\r\n")] = 0; printf("S: %s\n", r); }
    }
    waitpid(pid, NULL, 0); return 0;
}

আউটপুট:

S: 220 mx.example.org toy ESMTP
C: EHLO mail.example.com
S: 250 mx.example.org
C: MAIL FROM:<alice@example.com>
S: 250 OK
C: RCPT TO:<bob@example.org>
S: 250 OK
C: RCPT TO:<carol@example.org>
S: 550 5.1.1 no such user
C: DATA
S: 354 end with <CRLF>.<CRLF>
C: Subject: hi
C: 
C: ..starts with a dot
C: .
S: 250 OK: 3 lines, last: .starts with a dot
C: QUIT
S: 221 bye

এটি সত্যিকারের TCP সংযোগ — তারে প্রতিটি লাইনের শেষে \r\n গেছে, আর দুই দিকেই fgets() লাইন ধরে পড়েছে, ঠিক যেভাবে Postfix বা Exim পড়ে। প্রথম লাইন S: 220 … এসেছে ক্লায়েন্ট কিছু পাঠানোর আগেই (ক্লায়েন্টের লুপে i = -1 শুধু পড়ে)। RCPT TO:<carol…>-এ 550 5.1.1, কিন্তু সংযোগ চলতেই থাকে আর bob-এর জন্য DATA এগোয়। DATA-র তিনটি লাইনের পরে কোনো S: নেই; একক .-এর পরে সার্ভার জানাল 3 lines, আর শেষ লাইনটি .starts with a dot — তারে গিয়েছিল ..starts with a dot, সার্ভার একটি বিন্দু মুছে আসল লেখা রেখেছে। ফাঁকা লাইনটিও (header আর body-র মাঝের) একটি লাইন হিসেবে গোনা হয়েছে। শেষে waitpid() child-এর জন্য অপেক্ষা করে, যাতে কোনো zombie process না থাকে।

নিজের যন্ত্রে দেখতে চাইলে: নিজের ল্যাবে বা VM-এ একটি পরীক্ষামূলক সার্ভার (যেমন Postfix) বসিয়ে openssl s_client -starttls smtp -connect localhost:587 দিয়ে হাতে EHLO, AUTH লিখে দেখা যায়। এটি শুধু নিজের সার্ভারে করুন; অন্যের মেইল সার্ভারে হাতে চিঠি পাঠানো বা ঠিকানা আছে কি না যাচাই করা অনুচিত, অনেক জায়গায় নিষিদ্ধ, আর সেই সার্ভার আপনার IP-কে নিষিদ্ধ তালিকায় তুলতে পারে।

৭ · জাল প্রেরক ঠেকানো — SPF, DKIM আর DMARC

অংশ ৪-এ দেখেছেন, SMTP নিজে প্রেরকের পরিচয় যাচাই করে না। এর ফল phishing: ব্যাংক, মোবাইল ব্যাংকিং সেবা বা অফিসের IT বিভাগের নামে ভুয়া চিঠি, যাতে পাসওয়ার্ড বা OTP চাওয়া হয়। প্রতিরক্ষার তিনটি স্তর — তিনটিই DNS-এর TXT record-এ প্রকাশিত, আর প্রাপকের MX চিঠি গ্রহণের সময় যাচাই করে। এখানে আমরা শুধু প্রতিরক্ষার দিক দেখছি: নিজের ডোমেইন কীভাবে রক্ষা করবেন আর প্রাপক কীভাবে বিচার করে।

একটি বড় অফিসের চিঠি-ব্যবস্থা ভাবুন। SPF হলো অফিসের রিসেপশনে টাঙানো তালিকা: “আমাদের চিঠি বহন করেন শুধু এই পিয়নরা”। DKIM হলো খামের ভেতরের চিঠিতে অফিসের সিলমোহর — পথে কেউ খুলে বদলালে সিল ভেঙে যায়। DMARC হলো অফিসের প্রকাশ্য নির্দেশ: “আমাদের নামে আসা চিঠিতে তালিকার পিয়ন বা আমাদের সিল — অন্তত একটি থাকতে হবে, আর সেটা আমাদের নামেরই হতে হবে; না থাকলে ফেরত দিন, আর আমাদের জানান।”

SPF — কোন IP আমার ডোমেইনের চিঠি পাঠাতে পারে

SPF (Sender Policy Framework, RFC 7208, ২০১৪) ডোমেইনের TXT record-এ অনুমোদিত প্রেরকের তালিকা রাখে:

example.com.       TXT "v=spf1 ip4:192.0.2.0/24 include:_spf.example.com -all"
_spf.example.com.  TXT "v=spf1 ip4:198.51.100.0/25 -all"
  • প্রাপক SPF যাচাই করে envelope-এর MAIL FROM-এর ডোমেইন দিয়ে (খালি হলে EHLO-র নাম দিয়ে) — From: header দিয়ে নয়। এটিই SPF-এর বড় সীমা।
  • বাঁ থেকে ডানে প্রথম মিলে যাওয়া অংশই ফল দেয়। ip4:192.0.2.0/24 — 192.0.2.0 থেকে 192.0.2.255 (পর্ব ১৭-এর CIDR হিসাব)। include: মানে “ওই ডোমেইনের SPF-এ এই IP pass করলে মিল” — ভেতরের fail-এর মানে এখানে শুধু “মিলল না”, পুরো ফল fail নয়।
  • শেষের -all = বাকি সবাই fail (কড়া); ~all = softfail (সন্দেহজনক, সাধারণত গ্রহণ করে চিহ্ন দেয়); ?all = neutral. +all মানে “সবাই অনুমোদিত” — কখনো ব্যবহার করবেন না।
  • ১০-lookup সীমা: যেসব অংশে আরও DNS প্রশ্ন লাগে (include, a, mx, ptr, exists, redirect), সব মিলিয়ে ১০টির বেশি হলে ফল permerror — যেন কারও SPF দিয়ে অন্যের DNS-এ চাপ সৃষ্টি না করা যায়। অনেক বাইরের সেবা include করতে থাকলে এই সীমা সহজেই পেরোয়, তখন বৈধ চিঠিও ব্যর্থ হয়। একটি ডোমেইনে SPF record-ও একটিই থাকতে হবে।
  • দুর্বলতা: চিঠি forward হলে (যেমন bob@example.org নিজের চিঠি অন্য ঠিকানায় পাঠান) নতুন সংযোগের IP forward-কারীর, মূল প্রেরকের নয় — SPF fail করে।

DKIM — চিঠির ওপর ডিজিটাল সই

DKIM (DomainKeys Identified Mail, RFC 6376, ২০১১) Yahoo-র DomainKeys আর Cisco-র একটি প্রস্তাব মিলিয়ে তৈরি। পাঠানো সার্ভার নিজের গোপন key দিয়ে বার্তার কিছু header আর body-র hash-এর ওপর একটি ডিজিটাল সই দেয়, আর সেটি একটি নতুন header-এ যোগ করে:

DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com; s=sel2026;
    h=from:to:subject:date:message-id;
    bh=Wp3kq8...=;            ← body-র hash (base64)
    b=dK8sF2...=              ← সই (base64)
  • d= — কোন ডোমেইন সই দিচ্ছে; s= — selector, একই ডোমেইনের একাধিক key আলাদা করতে।
  • প্রাপক public key আনে DNS থেকে: sel2026._domainkey.example.com-এর TXT, যেমন "v=DKIM1; k=rsa; p=MIIBIjANBg…". সেই key দিয়ে সই যাচাই করে।
  • কী সই হয়: h=-তে তালিকাভুক্ত header (From: বাধ্যতামূলক) আর body-র hash. c=relaxed মানে ফাঁকা জায়গা বা header-এর বড়-ছোট হাতের অক্ষরের সামান্য বদল সহ্য করা হবে। খাম (MAIL FROM, RCPT TO) সই হয় না।
  • Forwarding-এ বার্তা না বদলালে DKIM টিকে থাকে — SPF-এর তুলনায় বড় সুবিধা। কিন্তু mailing list subject-এ “[তালিকা]” যোগ করলে বা নিচে footer বসালে সই ভাঙে।

Public key আর ডিজিটাল সইয়ের গণিত পর্ব ৪৭-এ, আর certificate ও TLS পর্ব ৪৮-এ। এখানে শুধু মনে রাখুন: গোপন key ছাড়া কেউ বৈধ সই বানাতে পারে না, কিন্তু DNS-এর public key দিয়ে যে কেউ যাচাই করতে পারে।

DMARC — নীতি আর alignment

SPF আর DKIM দুটিই কোনো একটি ডোমেইনকে “প্রমাণ” করে — কিন্তু সেটি পাঠকের দেখা From: ডোমেইন কি না, তা কেউ বলে না। প্রতারক নিজের ডোমেইন example.net-এর জন্য ঠিকঠাক SPF আর DKIM বানিয়ে From:-এ example.com লিখলে দুটিই pass! DMARC (RFC 7489, ২০১৫) এই ফাঁক বন্ধ করে। এটি _dmarc.example.com-এর TXT-এ থাকে:

_dmarc.example.com.  TXT "v=DMARC1; p=reject; rua=mailto:dmarc-reports@example.com; adkim=r; aspf=r"
  • DMARC pass = (SPF pass এবং SPF-এর ডোমেইন From:-এর সাথে aligned) অথবা (DKIM pass এবং d= From:-এর সাথে aligned).
  • Alignment: relaxed (r, ডিফল্ট) — একই organizational domain হলেই চলে (mail.example.com আর example.com মিলবে); strict (s) — হুবহু একই।
  • নীতি p=: none (শুধু পর্যবেক্ষণ আর রিপোর্ট), quarantine (spam/junk-এ পাঠানো), reject (SMTP-তেই প্রত্যাখ্যান)। চূড়ান্ত সিদ্ধান্ত প্রাপকের; নীতি একটি অনুরোধ।
  • রিপোর্ট: rua= ঠিকানায় প্রাপকেরা দিনে সাধারণত একবার XML aggregate report পাঠায় — কোন IP থেকে আপনার ডোমেইনের নামে কতগুলো চিঠি এল, কতগুলো pass/fail. এগুলো দেখেই প্রতিষ্ঠান বোঝে কোন বৈধ সেবা এখনো ঠিকমতো সাজানো নেই।

নিচের stepper-এ একটি “চতুর” জাল চিঠি: প্রতারক example.net ডোমেইনের মালিক, তার SPF আর DKIM দুটোই ঠিকঠাক, শুধু From:-এ লিখেছে example.com-এর নিরাপত্তা বিভাগের ঠিকানা।

Bob-এর MX চিঠিটি গ্রহণের আগে যাচাই করছে
যাচাই
দেখা তথ্য বা DNS প্রশ্ন
ফল
পাঠক কী দেখতেন (DMARC না থাকলে)
  1. চিঠি এল। সংযোগ 203.0.113.5 থেকে। খামে প্রেরক bounce@example.net, কিন্তু চিঠির ভেতরে From: “Example Security” <security@example.com>. Bob-এর অ্যাপ শুধু শেষেরটি দেখাবে। চিঠিতে একটি DKIM সই আছে, d=example.net.
  2. SPF: pass — কিন্তু কার জন্য? SPF যাচাই হয় খামের ডোমেইন example.net দিয়ে। তার record ip4:203.0.113.0/28: /২৮ মানে শেষ ৪ bit পরিবর্তনশীল, ২৪ = ১৬টি ঠিকানা, .০ থেকে .১৫. .৫ এর ভেতরে, তাই SPF pass. প্রতারক নিজের ডোমেইনে নিজের IP অনুমোদন করেছে — এতে অবৈধ কিছু নেই।
  3. DKIM: pass — আবার example.net-এর জন্য। Selector sel1 দিয়ে sel1._domainkey.example.net থেকে public key এনে সই মিলল। এটি শুধু প্রমাণ করে চিঠিটি example.net-এর key দিয়ে সই করা, আর পথে বদলায়নি।
  4. DMARC: alignment ব্যর্থ। পাঠকের দেখা ডোমেইন example.com, তাই প্রাপক _dmarc.example.com খোঁজে: p=reject. এবার প্রশ্ন: যে SPF pass করেছে তার ডোমেইন (example.net) কি example.com-এর সাথে aligned? না। যে DKIM pass করেছে তার d= (example.net)? না। কোনোটি aligned না হওয়ায় DMARC fail — দুটি “pass” থাকা সত্ত্বেও।
  5. নীতি প্রয়োগ। example.com বলেছে reject, তাই MX DATA-র পরে 550 5.7.1 দিয়ে চিঠি ফিরিয়ে দেয়। example.com-এর rua ঠিকানায় পরের aggregate report-এ থাকবে: “203.0.113.5 থেকে আপনার নামে ১টি চিঠি, DMARC fail, rejected”. DMARC না থাকলে এই চিঠি SPF আর DKIM দুটিতে pass নিয়ে Bob-এর INBOX-এ পৌঁছাতে পারত।

এবার একসাথে ছয়টি চিঠি। নিচের কোড DNS record-গুলো ডেটা হিসেবে নেয়, SPF নিজে হিসাব করে (ip4 পরিসর, include, -all/~all), DKIM-এর ফল ইনপুট হিসেবে নেয়, তারপর DMARC alignment আর নীতি থেকে চূড়ান্ত সিদ্ধান্ত দেয়।

// A receiving MX checks SPF (envelope MAIL FROM domain), DKIM (given) and DMARC (header From: domain).
const TXT = {                                   // DNS TXT records, given as data (no real DNS)
  "example.com":        "v=spf1 ip4:192.0.2.0/24 include:_spf.example.com -all",
  "_spf.example.com":   "v=spf1 ip4:198.51.100.0/25 -all",
  "example.net":        "v=spf1 ip4:203.0.113.0/28 -all",
  "example.org":        "v=spf1 ip4:198.51.100.128/25 ~all",
  "_dmarc.example.com": "v=DMARC1; p=reject; rua=mailto:dmarc-reports@example.com",
  "_dmarc.example.org": "v=DMARC1; p=quarantine" };
const ip2n = (ip) => ip.split(".").reduce((n, o) => n * 256 + +o, 0);
const inNet = (ip, c) => { const [net, len = 32] = c.split("/"), k = 2 ** (32 - len);
  return Math.floor(ip2n(ip) / k) === Math.floor(ip2n(net) / k); };
function spf(domain, ip) {                      // pass / fail / softfail / neutral / none
  const rec = TXT[domain]; if (!rec) return "none";
  for (const term of rec.split(" ").slice(1)) {
    const [mech, arg] = term.split(":");
    if (mech === "ip4" && inNet(ip, arg)) return "pass";
    if (mech === "include" && spf(arg, ip) === "pass") return "pass";  // only a pass there matches
    if (mech === "-all" || mech === "~all") return mech === "-all" ? "fail" : "softfail";
  } return "neutral";
}
const org = (d) => d.split(".").slice(-2).join(".");    // simplification of the Public Suffix List
const row = (...v) => v.map((x, i) => String(x).padEnd([16, 10, 9, 9, 7, 11][i])).join("");
const msgs = [ // label, connecting IP, envelope MAIL FROM domain, header From: domain, DKIM result d=
  ["1 own server", "192.0.2.25", "example.com", "example.com", "pass example.com"],
  ["2 via include", "198.51.100.20", "example.com", "example.com", "none"],
  ["3 crude spoof", "203.0.113.99", "example.com", "example.com", "none"],
  ["4 clever spoof", "203.0.113.5", "example.net", "example.com", "pass example.net"],
  ["5 forwarded", "203.0.113.77", "example.com", "example.com", "pass example.com"],
  ["6 org softfail", "192.0.2.99", "example.org", "example.org", "none"] ];
console.log(row("message", "SPF", "SPF-al", "DKIM-al", "DMARC", "policy") + "-> action");
for (const [label, ip, mfrom, from, dkim] of msgs) {
  const s = spf(mfrom, ip), [dres, dd = ""] = dkim.split(" "), rec = TXT["_dmarc." + org(from)];
  const sAl = s === "pass" && org(mfrom) === org(from), dAl = dres === "pass" && org(dd) === org(from);
  const p = rec ? rec.match(/p=(\w+)/)[1] : "(none)", ok = sAl || dAl;
  console.log(row(label, s, sAl, dAl, ok ? "pass" : "fail", p) + "-> " + (ok || p === "none" || !rec ? "deliver" : p)); }

আউটপুট:

message         SPF       SPF-al   DKIM-al  DMARC  policy     -> action
1 own server    pass      true     true     pass   reject     -> deliver
2 via include   pass      true     false    pass   reject     -> deliver
3 crude spoof   fail      false    false    fail   reject     -> reject
4 clever spoof  pass      false    false    fail   reject     -> reject
5 forwarded     fail      false    true     pass   reject     -> deliver
6 org softfail  softfail  false    false    fail   quarantine -> quarantine

সারি ১: নিজের সার্ভার, সব মিলেছে। সারি ২: 198.51.100.20 example.com-এর নিজের /২৪-এ নেই, কিন্তু include:_spf.example.com-এর 198.51.100.0/25 (.০–.১২৭)-এ আছে — SPF pass, DKIM নেই, তবু একটি aligned pass যথেষ্ট। সারি ৩: অচেনা IP থেকে কাঁচা নকল — SPF fail, কিছু aligned নয়, reject. সারি ৪: ওপরের stepper-এর চতুর নকল — SPF pass হলেও SPF-al false, তাই reject. সারি ৫: forward হওয়া বৈধ চিঠি — নতুন IP বলে SPF fail, কিন্তু DKIM অক্ষত আর aligned, তাই DMARC pass. এটাই দেখায় কেন DKIM ছাড়া শুধু SPF-এ ভরসা বিপজ্জনক। সারি ৬: example.org-এর record ~all, IP তালিকায় নেই → softfail; DMARC fail, আর example.org-এর নীতি quarantine — চিঠি junk ফোল্ডারে। (Organizational domain এখানে “শেষ দুই অংশ” ধরে সরল করা হয়েছে; বাস্তবে Public Suffix List লাগে, নইলে .com.bd-এর মতো ডোমেইনে ভুল হবে।)

মূল ধারণা

SPF আর DKIM প্রশ্নের উত্তর দেয় “কোনো একটি ডোমেইন কি এই চিঠির দায় নিচ্ছে?” DMARC প্রশ্ন করে “যে ডোমেইনের নাম পাঠক দেখছেন, সে-ই কি দায় নিচ্ছে?” একটি ডোমেইন রক্ষা করতে তিনটিই লাগে, আর DMARC-এর নীতি none থেকে রিপোর্ট দেখে দেখে ধীরে quarantine আর reject-এ নেওয়াই নিরাপদ পথ।

৮ · পথের নিরাপত্তা, end-to-end, spam আর বড় প্রেরকদের নিয়ম

ARC — forward আর mailing list-এর সমস্যা

Mailing list চিঠি বদলালে DKIM আর SPF দুটিই ভাঙতে পারে। ARC (Authenticated Received Chain, RFC 8617, ২০১৯, experimental) এর একটি আংশিক উত্তর: প্রতিটি মধ্যবর্তী সার্ভার নিজের দেখা যাচাইয়ের ফল (“আমি পেয়েছিলাম তখন DKIM pass ছিল”) নিজের সই দিয়ে যোগ করে। মধ্যবর্তীকে বিশ্বাস করবে কি না, তা শেষ প্রাপকের সিদ্ধান্ত।

STARTTLS-এর দুর্বলতা, MTA-STS আর DANE

Port 25-এ STARTTLS ঐচ্ছিক (opportunistic): সার্ভার EHLO-র উত্তরে STARTTLS ঘোষণা করলে ক্লায়েন্ট এনক্রিপশনে যায়, না করলে সাধারণ লেখায় পাঠায়। যেহেতু ঘোষণাটি নিজেই এনক্রিপ্ট-হীন, পথের একজন আক্রমণকারী (MITM) “250 STARTTLS” লাইনটি মুছে দিলে দুই সার্ভার কিছু টের না পেয়েই খোলা লেখায় কথা বলে — এটি downgrade-এর ঝুঁকি। আর certificate যাচাই না করলে নকল সার্ভারও TLS দিতে পারে। দুটি প্রতিরক্ষা:

  • MTA-STS (RFC 8461, ২০১৮): ডোমেইন HTTPS-এ একটি নীতি-ফাইল প্রকাশ করে — “আমার MX এগুলো, আর এদের সাথে বৈধ certificate-সহ TLS ছাড়া পাঠাবেন না”। প্রেরক নীতিটি কিছুদিন মনে রাখে। সাথে TLS-RPT (RFC 8460) দিয়ে TLS ব্যর্থতার রিপোর্ট আসে।
  • DANE (SMTP-র জন্য RFC 7672): MX-এর certificate-এর ছাপ DNS-এর TLSA record-এ থাকে, আর DNSSEC দিয়ে তা স্বাক্ষরিত — প্রেরক DNS থেকেই জানে কোন certificate আশা করবে। শর্ত: ডোমেইনে DNSSEC চালু থাকতে হবে।

End-to-end encryption — PGP আর S/MIME

STARTTLS শুধু পথ ঢাকে; প্রতিটি সার্ভারে আর mailbox-এ চিঠি সরবরাহকারীর কাছে খোলা থাকে। প্রেরক থেকে প্রাপক পর্যন্ত গোপন রাখতে body-ই এনক্রিপ্ট করতে হয়: PGP (মান OpenPGP) বা S/MIME (certificate-ভিত্তিক)। দুটিতেই প্রাপকের public key আগে জানতে হয়, আর header (Subject, প্রাপক) সাধারণত খোলা থাকে — বিস্তারিত ভাবনার প্রশ্ন ০৪-এ।

Spam filter — সংক্ষেপে

প্রাপকের MX কয়েক স্তরে বিচার করে: সংযোগের IP আর ডোমেইনের সুনাম (অতীতের spam, নিষিদ্ধ তালিকা, reverse DNS), SPF/DKIM/DMARC-এর ফল, SMTP আচরণ (greylisting-এ আবার চেষ্টা করে কি না), আর বিষয়বস্তু — লিংক, সংযুক্তির ধরন, আর ব্যবহারকারীদের “Spam” বোতাম থেকে শেখা মডেল। কোনো একক পরীক্ষা চূড়ান্ত নয়; নম্বর জমে, সীমা পেরোলে junk বা প্রত্যাখ্যান।

বড় প্রেরকদের নতুন নিয়ম (২০২৪ থেকে)

Google আর Yahoo ২০২৩ সালের শেষে ঘোষণা দেয়, আর ২০২৪ সালের শুরু থেকে প্রয়োগ শুরু করে: যারা দিনে প্রায় ৫,০০০-এর বেশি চিঠি তাদের ব্যবহারকারীদের পাঠায়, তাদের SPF আর DKIM দুটোই থাকতে হবে, অন্তত p=none-এর DMARC থাকতে হবে আর From: ডোমেইন aligned হতে হবে, বিপণনের চিঠিতে এক-ক্লিকে unsubscribe (RFC 8058) থাকতে হবে, আর ব্যবহারকারীর spam-রিপোর্টের হার খুব কম (প্রায় ০.৩%-এর নিচে) রাখতে হবে। পরে Microsoft-ও নিজের ভোক্তা মেইলের জন্য অনুরূপ শর্ত ঘোষণা করে। সীমা আর শর্তের খুঁটিনাটি সময়ের সাথে বদলায় — নিজের প্রতিষ্ঠানের জন্য প্রতিটি সরবরাহকারীর বর্তমান নির্দেশিকা দেখে নিন।

আরও গভীরে: Postfix-এর মতো MTA আসলে কয়েকটি ছোট process-এর সমষ্টি — একটি port 25-এ শোনে, একটি queue পরিচালনা করে, একটি বাইরে পাঠায় — আর queue-র ফাইল ডিস্কে fsync করার পরেই 250 দেয়, যাতে বিদ্যুৎ চলে গেলেও গৃহীত চিঠি না হারায়। RFC 3463-এর enhanced status code (যেমন 5.7.1 = নীতিগত প্রত্যাখ্যান) আর RFC 3464-এর DSN-বিন্যাস bounce-কে যন্ত্রে পড়ার যোগ্য করে। DMARC-এর একটি হালনাগাদ সংস্করণ নিয়ে IETF-এ কাজ হয়েছে, যাতে organizational domain খোঁজার পদ্ধতিসহ কিছু নিয়ম বদলায় — বাস্তবায়নের আগে সর্বশেষ নথি মিলিয়ে নিন।

পরীক্ষা ও ইন্টারভিউতে এই বিষয়ে প্রায়ই যা জিজ্ঞেস করা হয়:

  • SMTP, POP3, IMAP-এর পার্থক্য আর port? — SMTP পাঠায় (25 relay, 587/465 submission); POP3 (110/995) নামিয়ে মুছে দেয়; IMAP (143/993) সার্ভারে রেখে সব যন্ত্রে sync করে।
  • ইমেইল push না pull? — পাঠানো (SMTP) push, পড়া (IMAP/POP3) pull.
  • MX-এ preference 10 আর 20 থাকলে কোনটি আগে? — ১০, কারণ ছোট সংখ্যা বেশি পছন্দের; ব্যর্থ হলে ২০.
  • 4xx আর 5xx-এর পার্থক্য? — 4xx সাময়িক, MTA queue-তে রেখে আবার চেষ্টা করে; 5xx স্থায়ী, প্রেরককে bounce.
  • SPF pass হলেও চিঠি জাল হতে পারে কেন? — SPF খামের MAIL FROM যাচাই করে, From: নয়; DMARC alignment ছাড়া From: সুরক্ষিত নয়।

৯ · AI-এর যুগে ইমেইল — DNS record লেখানো আর যাচাই করা

“আমার ডোমেইনের জন্য SPF, DKIM, DMARC বানিয়ে দিন” — AI কয়েক সেকেন্ডে record লিখে দেয়। কিন্তু আপনার প্রতিষ্ঠান কোন কোন সেবা দিয়ে চিঠি পাঠায় (অফিসের মেইল, বিল পাঠানোর সফটওয়্যার, নিউজলেটার), তা AI জানে না। একটি ভুল record-এ নিজের বৈধ চিঠি junk-এ যায়, আর একটি ঢিলা record-এ প্রতারক আপনার নাম ব্যবহার করে। চেনা ভুলগুলো:

AI-এর ভুলআসল কথাকীভাবে যাচাই করবেন
“SPF From: header যাচাই করে”SPF খামের MAIL FROM (বা EHLO) যাচাই করে; From:-এর সাথে যোগ ঘটায় DMARCRFC 7208 আর RFC 7489-এর সংজ্ঞা
সমস্যা হলে v=spf1 +all বা দুটি আলাদা SPF record+all সবাইকে অনুমতি দেয়; দুটি record হলে permerrorDNS-এ শুধু একটি v=spf1 আছে কি না দেখুন
অনেকগুলো include জুড়ে দেওয়াDNS lookup ১০-এর বেশি হলে permerrorপ্রতিটি include-এর ভেতরের record গুনে দেখুন
প্রথম দিনেই p=rejectঅজানা বৈধ সেবার চিঠি হারাবে; আগে p=none আর রিপোর্টকয়েক সপ্তাহের aggregate report দেখে ধীরে এগোন
বানানো DKIM tag বা RFC নম্বর, “port 465 বাতিল”-এর মতো পুরোনো দাবিDKIM-এর tag RFC 6376-এ নির্দিষ্ট; 465 এখন RFC 8314-এ সুপারিশকৃতrfc-editor.org-এ নম্বর আর শিরোনাম মেলান
মেইল সার্ভার কনফিগে “সব নেটওয়ার্ক থেকে relay অনুমতি”এটি open relay — কয়েক ঘণ্টায় spam-এর উৎস আর নিষিদ্ধ তালিকানিজের ল্যাবে বাইরের ঠিকানা থেকে relay প্রত্যাখ্যাত হয় কি না দেখুন

AI-কে কাজে লাগান, কিন্তু আপনার প্রেক্ষাপট দিয়ে, আর প্রতিটি দাবির সূত্র চেয়ে:

তুমি একজন অভিজ্ঞ মেইল-সিস্টেম প্রশাসকের মতো উত্তর দাও। আমার ডোমেইন example.com. চিঠি যায় তিনভাবে: অফিসের সার্ভার 192.0.2.10, একটি নিউজলেটার সেবা যার SPF record _spf.example.net-এ, আর একটি বিলিং সফটওয়্যার যা নিজের DKIM selector "bill" দিয়ে সই করে। ১. একটিমাত্র SPF record লেখো আর DNS lookup কয়টি লাগবে গুনে দেখাও। ২. DMARC record লেখো p=none আর রিপোর্টসহ; কয় সপ্তাহ পরে কোন তথ্য দেখে quarantine আর reject-এ যাব, তার পরিকল্পনা দাও। ৩. প্রতিটি tag-এর অর্থ আর RFC নম্বর (7208, 6376, 7489) উল্লেখ করো; নিশ্চিত না হলে স্পষ্ট বলো। ৪. কোন পরামর্শ নিরাপত্তা ঢিলা করতে পারে (যেমন +all, open relay), তা আলাদা করে সতর্ক করো।

AI-এর ইমেইল-পরামর্শ চালুর আগে — চেকলিস্ট

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন।

প্র ০১১৯৮২ সালের SMTP-তে প্রেরকের পরিচয় যাচাইয়ের কোনো ব্যবস্থা ছিল না কেন? চার দশক পরে সেই ফাঁক জোড়া লাগাতে এত স্তর লাগল কেন?

RFC 821 লেখা হয়েছিল ARPANET-এর জন্য — কয়েকশো যন্ত্র, প্রায় সবাই গবেষণা প্রতিষ্ঠান আর সরকারি সংস্থার, যাদের ব্যবহারকারীরা একে অপরকে চিনতেন বা অন্তত একই সম্প্রদায়ের। সেখানে সবচেয়ে বড় চ্যালেঞ্জ ছিল নির্ভরযোগ্যতা: অনিয়মিত সংযোগের মাঝ দিয়ে চিঠি কীভাবে হারানো ছাড়া পৌঁছাবে। তাই নকশার কেন্দ্রে store-and-forward, retry queue আর relay — যেকোনো সার্ভার যেকোনো চিঠি সামনে এগিয়ে দিতে পারে, যাতে সরাসরি পথ না থাকলেও চিঠি পৌঁছায়। প্রতারণা তখন প্রায় অকল্পনীয় সমস্যা; বাণিজ্যিক ব্যবহারও নিষিদ্ধ ছিল। ১৯৭৮ সালে ARPANET-এ একটি কোম্পানির পণ্যের বিজ্ঞাপন শত শত ঠিকানায় পাঠানোর ঘটনা প্রায়ই প্রথম “spam” হিসেবে উল্লেখ করা হয় — আর তখন তার প্রতিকার ছিল প্রশাসনিক ভর্ৎসনা, প্রযুক্তি নয়।

১৯৯০-এর দশকে ইন্টারনেট বাণিজ্যিক আর সর্বজনীন হলো। খোলা relay আর যাচাই-হীন From: হয়ে উঠল spammer আর প্রতারকের স্বর্গ। কিন্তু ততদিনে লাখো সার্ভার চলছে; protocol বদলে “প্রমাণ ছাড়া চিঠি নেব না” বলা মানে পুরোনো সব ব্যবস্থার সাথে যোগাযোগ বন্ধ। তাই সমাধান এল ধাপে ধাপে, প্রতিটি পেছনের সাথে সামঞ্জস্য রেখে: প্রথমে relay বন্ধ আর submission-এ AUTH, তারপর DNS-এ প্রকাশিত নীতি — SPF (IP-র তালিকা), DKIM (সই), আর এদের জোড়া দিতে DMARC. প্রতিটি স্তর ঐচ্ছিক, যাতে যে ব্যবহার করে না তার চিঠি অন্তত চলে। এই ঐচ্ছিকতাই আবার দুর্বলতা — যতক্ষণ বেশিরভাগ ডোমেইন p=none রাখে, প্রাপক কড়া হতে পারে না।

শেষ পর্যন্ত চাপ এল বাজার থেকে: বড় মেইল সরবরাহকারীরা ২০২৪ থেকে বিপুল প্রেরকদের জন্য এই স্তরগুলো বাধ্যতামূলক করল। এটি একটি পরিচিত ইন্টারনেট-নকশা: মূল protocol না বদলে ওপরে একটি স্তর, আর তা কার্যকর হয় যখন যথেষ্ট বড় খেলোয়াড় সেটি দাবি করে।

মূল উপলব্ধি: নিরাপত্তা পরে যোগ করা সম্ভব, কিন্তু তখন তা টুকরো টুকরো, ঐচ্ছিক আর ধীর হয় — কারণ প্রতিটি ধাপকে পুরোনো পৃথিবীর সাথে মিলে চলতে হয়। নতুন protocol নকশায় পরিচয় যাচাইয়ের প্রশ্ন প্রথম দিনেই তোলা উচিত।

প্র ০২SPF আর DKIM থাকতে DMARC কেন লাগল? Forwarding আর mailing list-এর সাথে এই তিনটির টানাপোড়েন ব্যাখ্যা করুন।

SPF আর DKIM দুটিই “কোনো একটি ডোমেইন” প্রমাণ করে, কিন্তু কোনোটিই সেই ডোমেইনকে পাঠকের দেখা From:-এর সাথে বাঁধে না। SPF দেখে খামের MAIL FROM — যা সাধারণ ব্যবহারকারী কখনো দেখেন না। DKIM-এর d= যেকোনো ডোমেইন হতে পারে। তাই প্রতারক নিজের ডোমেইনে নিখুঁত SPF আর DKIM রেখে From:-এ ব্যাংকের নাম লিখলে দুটি “pass” পায়। ২০১২ সালের দিকে কয়েকটি বড় মেইল সরবরাহকারী আর ঘনঘন phishing-এর শিকার কিছু প্রতিষ্ঠান মিলে DMARC তৈরি করে, ২০১৫ সালে তা RFC 7489 হয়। এর তিনটি অবদান: alignment (pass-এর ডোমেইন From:-এর সাথে মিলতে হবে), ডোমেইন-মালিকের প্রকাশ্য নীতি (none/quarantine/reject), আর রিপোর্ট — যা ছাড়া মালিক জানতেই পারতেন না কারা তাঁর নামে পাঠাচ্ছে।

টানাপোড়েন আসে মাঝের সার্ভার থেকে। কেউ নিজের অফিসের চিঠি ব্যক্তিগত ঠিকানায় forward করলে নতুন সংযোগের IP forward-কারীর — SPF ব্যর্থ। Mailing list প্রায়ই subject-এ তালিকার নাম জোড়ে বা নিচে footer বসায় — DKIM-এর body hash ভেঙে যায়। তখন p=reject থাকা ডোমেইনের কোনো সদস্য তালিকায় লিখলে অন্য সদস্যরা চিঠি পান না। ২০১৪ সালে দুটি বড় সরবরাহকারী নিজেদের ডোমেইনে p=reject দেওয়ার পর বহু mailing list-এ এই সমস্যা ব্যাপকভাবে দেখা দিয়েছিল বলে জানা যায়। সমাধান হিসেবে অনেক তালিকা এখন From: বদলে নিজের ঠিকানা বসায় (“Alice via তালিকা”), আর ARC মধ্যবর্তী সার্ভারের দেখা ফল সই করে এগিয়ে দেয়।

এখান থেকে একটি ব্যবহারিক নীতি বেরোয়: নিজের ডোমেইন রক্ষায় DKIM-কে প্রধান ভরসা রাখুন, কারণ forwarding-এ সেটিই টেকে; SPF সহায়ক। আর DMARC চালু করুন p=none দিয়ে, রিপোর্ট পড়ে সব বৈধ প্রেরককে aligned করুন, তারপর ধীরে কড়া করুন।

মূল উপলব্ধি: প্রতিটি যাচাই একটি নির্দিষ্ট প্রশ্নের উত্তর দেয়; কোন প্রশ্ন আসলে গুরুত্বপূর্ণ — “পাঠক যাকে দেখছেন সে-ই কি পাঠিয়েছে?” — সেটি না জুড়লে দুটি সঠিক যাচাইও ভুল নিরাপত্তার অনুভূতি দেয়।

প্র ০৩POP3 থেকে IMAP, তারপর webmail আর JMAP — ইমেইল পড়ার protocol-এর বিবর্তন ব্যবহারকারীর যন্ত্র আর নেটওয়ার্কের বদলের সাথে কীভাবে মেলে?

POP-এর প্রথম সংস্করণ ১৯৮৪ সালের, আর POP3-এর বর্তমান মান RFC 1939 (১৯৯৬)। তখনকার ব্যবহারকারীর একটি ডেস্কটপ কম্পিউটার, আর ইন্টারনেট মানে ফোনলাইনের ডায়াল-আপ, প্রায়ই মিনিট হিসাবে বিল। সেরা নকশা তাই: সংযোগ দেওয়া, সব চিঠি নামানো, সার্ভার থেকে মোছা, সংযোগ ছাড়া — তারপর অফলাইনে পড়া। সার্ভারের ডিস্কও তখন দামি, তাই চিঠি জমিয়ে রাখা সার্ভারের দায় নয়।

IMAP-এর নকশা শুরু ১৯৮৬ সালে Mark Crispin-এর হাতে, আর এর ভাবনা ভিন্ন: চিঠির আসল ঘর সার্ভার, অ্যাপ শুধু জানালা। ফোল্ডার, পড়া-না-পড়া চিহ্ন, অনুসন্ধান — সব সার্ভারে। শুরুতে এটি বিশ্ববিদ্যালয় আর প্রতিষ্ঠানে জনপ্রিয় হয়, যেখানে একজন ল্যাবের নানা কম্পিউটারে বসতেন। স্মার্টফোন আসার পর IMAP প্রায় বাধ্যতামূলক হয়ে দাঁড়াল: একজন মানুষের তিন-চারটি যন্ত্র, আর প্রত্যেকটিতে একই অবস্থা চাই। IDLE এক্সটেনশন সংযোগ খোলা রেখে নতুন চিঠির খবর দেয়, কিন্তু মোবাইলে দীর্ঘ খোলা সংযোগ ব্যাটারি খায় আর NAT-এর timeout-এ (পর্ব ১৯) ভাঙে।

এরপর দুটি দিক। Webmail (১৯৯০-এর দশকের মাঝামাঝি থেকে; ২০০৪ সালে বিপুল জায়গা দিয়ে আসা Gmail এর জনপ্রিয়তা বাড়ায়) পড়ার protocol-কে পুরোপুরি HTTP-র পেছনে লুকিয়ে ফেলে — ব্যবহারকারীর কিছু সেট করতে হয় না, firewall-ও শুধু HTTPS চেনে। অন্যদিকে JMAP (২০১৯) IMAP-এর ধারণাগুলো JSON আর HTTP-তে নতুন করে লেখে, একবারে অনেক কাজ পাঠানো আর push notification সহজ করে, যা মোবাইলের জন্য দক্ষ। IMAP-ও থেমে নেই — IMAP4rev2 (RFC 9051, ২০২১) বহু এক্সটেনশন মূল মানে এনেছে।

মূল উপলব্ধি: protocol-এর নকশা প্রতিফলিত করে তার সময়ের সীমাবদ্ধতা — দামি সংযোগ ও ডিস্কে “নামানো আর মোছা”, অনেক যন্ত্রে “সার্ভারেই রাখা”, মোবাইল আর ব্রাউজারে “HTTP-র ওপর দিয়ে”। পুরোনোটি ভুল নয়; শুধু অন্য পৃথিবীর জন্য ঠিক ছিল।

প্র ০৪STARTTLS প্রায় সব সার্ভারে চালু, তবু বলা হয় ইমেইল “end-to-end” গোপন নয়। আর PGP-র মতো end-to-end ব্যবস্থা তিন দশকেও সাধারণ মানুষের কাছে পৌঁছাল না কেন?

STARTTLS (২০০২ সালের RFC 3207) প্রতিটি পথের অংশ এনক্রিপ্ট করে: MUA থেকে MSA, MTA থেকে MTA. কিন্তু প্রতিটি সার্ভারে চিঠি খোলা অবস্থায় থাকে — প্রেরকের সরবরাহকারী, প্রাপকের সরবরাহকারী, মাঝের যেকোনো relay সব পড়তে পারে, আর mailbox-এ বছরের পর বছর জমা থাকে। তার ওপর port 25-এর STARTTLS ঐচ্ছিক: সার্ভারগুলো ঐতিহাসিকভাবে certificate কড়াভাবে যাচাই করত না, কারণ করলে অসংখ্য ভুল-সাজানো সার্ভারের সাথে চিঠি আদান-প্রদান থেমে যেত। পথের কেউ STARTTLS ঘোষণা মুছে দিলে downgrade হয়। MTA-STS আর DANE এই পথের অংশটি শক্ত করে, কিন্তু সার্ভারে খোলা থাকার প্রশ্ন থেকেই যায়।

End-to-end এনক্রিপশন — প্রেরক প্রাপকের public key দিয়ে body এনক্রিপ্ট করেন, শুধু প্রাপকের গোপন key তা খোলে — ১৯৯১ সালে Phil Zimmermann-এর PGP দিয়ে সাধারণ মানুষের হাতে আসে। প্রযুক্তি শক্ত, কিন্তু ব্যবহার কঠিন। ১৯৯৯ সালের একটি বিখ্যাত গবেষণাপত্র “Why Johnny Can't Encrypt” (Whitten ও Tygar) দেখিয়েছিল, সাধারণ ব্যবহারকারীরা নির্দেশনা পেয়েও প্রায়ই ভুল key ব্যবহার করেন বা গোপন key ফাঁস করে ফেলেন। Key খুঁজে পাওয়া, যাচাই করা, হারালে পুরোনো চিঠি চিরতরে হারানো, webmail-এ সার্ভারে খোলা যায় না বলে অনুসন্ধান না চলা, আর header (Subject, প্রাপক) খোলা থাকা — সব মিলিয়ে বাধা অনেক। S/MIME প্রতিষ্ঠানে কিছুটা চলে, কারণ সেখানে IT বিভাগ certificate বিতরণ করে।

তুলনায় মেসেজিং অ্যাপগুলো end-to-end এনক্রিপশন কোটি মানুষের কাছে পৌঁছেছে, কারণ সেখানে একটি প্রতিষ্ঠান দুই প্রান্তের অ্যাপ আর key বিতরণ দুটোই নিয়ন্ত্রণ করে, ব্যবহারকারীকে কিছু করতে হয় না। ইমেইলের শক্তি — কেউ একা মালিক নয়, যেকোনো সার্ভার যেকোনো সার্ভারের সাথে কথা বলে — এখানেই দুর্বলতা।

মূল উপলব্ধি: নিরাপত্তা প্রযুক্তির সাফল্য গণিতের চেয়ে বেশি নির্ভর করে key-ব্যবস্থাপনা আর ব্যবহারের সহজতার ওপর। ইমেইলে গোপন কিছু পাঠানোর আগে ধরে নিন সরবরাহকারীরা তা পড়তে পারেন।

প্র ০৫একটি ছোট প্রতিষ্ঠান নিজের সার্ভারে ইমেইল চালাতে চায়, বড় সরবরাহকারীর ওপর নির্ভর না করে। আজকের ইন্টারনেটে এটি কেন কঠিন, আর এর মানে ইমেইলের “বিকেন্দ্রীকরণ”-এর জন্য কী?

প্রযুক্তিগতভাবে কাজটি জানা: একটি Linux সার্ভারে Postfix বা Exim, IMAP-এর জন্য Dovecot, spam filter, TLS certificate, আর DNS-এ MX, SPF, DKIM, DMARC. কয়েক দিনে চালু করা যায়। কঠিন অংশ শুরু হয় চিঠি পৌঁছানো-য়। বড় প্রাপকেরা নতুন বা অচেনা IP-কে সন্দেহের চোখে দেখে — সুনাম নেই, তাই চিঠি junk-এ বা সাময়িক প্রত্যাখ্যানে পড়ে। IP যদি এমন ঠিকানার পরিসরে হয় যেখান থেকে অতীতে spam এসেছে, বা ক্লাউডের এমন অংশে যা নিষিদ্ধ তালিকায় আছে, তাহলে আরও কঠিন। Reverse DNS (PTR) ঠিক না থাকলে, বা বাসা/অফিসের সাধারণ সংযোগ হলে (port 25 বন্ধ, dynamic IP), শুরুই করা যায় না।

তারপর আছে চলমান দায়িত্ব: নিরাপত্তা হালনাগাদ, ডিস্ক আর ব্যাকআপ, DMARC রিপোর্ট পড়া, কোনো ব্যবহারকারীর পাসওয়ার্ড চুরি হলে সার্ভার থেকে spam বেরোনো ঠেকানো — নইলে পুরো প্রতিষ্ঠানের IP নিষিদ্ধ তালিকায়। ২০২৪-এর পর বড় সরবরাহকারীদের শর্তগুলো (SPF, DKIM, DMARC alignment, কম spam-হার) ভালো অভ্যাস হলেও ছোট প্রশাসকের জন্য আরও কাজ।

ফলে বাস্তবে বেশিরভাগ প্রতিষ্ঠান — বাংলাদেশেও — নিজের ডোমেইন রেখে মেইল চালায় বড় ক্লাউড সরবরাহকারীর মাধ্যমে, অথবা নিজের সার্ভার রেখে বাইরে পাঠানোর জন্য একটি সুনামধারী relay সেবা ব্যবহার করে। এতে চিঠি পৌঁছানো নিশ্চিত হয়, কিন্তু একটি দাম আছে: পৃথিবীর বড় অংশের চিঠি গুটিকয়েক প্রতিষ্ঠানের হাতে, তাদের নীতিই কার্যত মান হয়ে ওঠে, আর ছোট খেলোয়াড়ের প্রবেশ কঠিন। প্রোটোকল খোলা ও বিকেন্দ্রীকৃতই আছে — যে কেউ MX চালাতে পারে — কিন্তু spam-বিরোধী সুনাম-ব্যবস্থা অর্থনৈতিকভাবে কেন্দ্রীকরণের দিকে টানে।

মূল উপলব্ধি: একটি protocol উন্মুক্ত হলেই ব্যবস্থাটি বিকেন্দ্রীকৃত থাকে না; অপব্যবহার ঠেকানোর খরচ যার কাছে সবচেয়ে কম, শেষে নিয়ন্ত্রণ তার দিকেই সরে। নিজের ডোমেইন নিজের হাতে রাখাই সবচেয়ে কাজের স্বাধীনতা — সরবরাহকারী বদলালে ঠিকানা বদলায় না।

অনুশীলন

খাতা-কলম নিন — bit, CIDR আর SMTP-র লাইন ধরে ধরে হিসাব করুন।

  1. হাতে base64: (ক) “Man” শব্দটি base64-এ লিখুন (M = 0x4D, a = 0x61, n = 0x6E). (খ) “ঢা”-র UTF-8 বাইট E0 A6 A2 E0 A6 BE. এর base64 কত অক্ষর হবে, শেষে = থাকবে কি না? (গ) ৩০০ বাইটের একটি ফাইল base64-এ কত অক্ষর হবে, আর ৭৬ অক্ষরের লাইনে ভাঙলে কয়টি লাইন?

    (ক) 01001101 01100001 01101110 → 010011 010110 000101 101110 → ১৯, ২২, ৫, ৪৬ → T, W, F, (৪৬ − ২৬ = ২০ → u) = TWFu.

    (খ) ৬ বাইট = ঠিক দুটি তিন-বাইটের দল → ৮ অক্ষর, কোনো = নেই: 4Kai4Ka+ (অংশ ৫-এর subject-এর প্রথম ৮ অক্ষরের সাথে মিলিয়ে দেখুন)।

    (গ) ৩০০ ÷ ৩ = ১০০ দল → ৪০০ অক্ষর, padding নেই। ৪০০ ÷ ৭৬ = ৫.২৬ → ৬টি লাইন (৫টি পূর্ণ ৭৬ অক্ষরের, শেষটিতে ৪০০ − ৩৮০ = ২০ অক্ষর)।

  2. SPF হাতে বিচার: example.com-এর record v=spf1 ip4:192.0.2.64/26 include:_spf.example.net ~all, আর _spf.example.net-এর record v=spf1 ip4:198.51.100.0/24 -all. MAIL FROM-এর ডোমেইন example.com হলে নিচের IP-গুলোর SPF ফল কী? (ক) 192.0.2.100 (খ) 192.0.2.130 (গ) 198.51.100.7. আর এই record-এ DNS lookup-এর হিসাবে কয়টি গোনা হয়?

    /২৬ মানে শেষ ৬ bit পরিবর্তনশীল = ৬৪টি ঠিকানা; 192.0.2.64/26 = .৬৪ থেকে .১২৭.

    (ক) .১০০ পরিসরের ভেতরে → pass. (খ) .১৩০ বাইরে; include-এ 198.51.100.0/24-এ নেই, ভেতরের ফল fail, তাই include “মিলল না”; শেষে ~all → softfail (ভেতরের -all বাইরের ফল ঠিক করে না)। (গ) প্রথম অংশে নেই, include-এর ভেতরে pass → pass.

    Lookup গোনা হয় শুধু include (আর a, mx, ptr, exists, redirect)-এর জন্য: এখানে ১টি. ip4 আর all নতুন DNS প্রশ্ন করে না।

  3. আউটপুট অনুমান করুন: অংশ ৩-এর SMTP simulator-এ শুধু শেষ লুপের তালিকা [[0, true], [30, false]] বদলে [[0, false]] করা হলো (একটিমাত্র চেষ্টা, greylisting নেই)। RCPT-এর উত্তরগুলো, বন্ধনীর নোট আর শেষ দুটি S: লাইন কী হবে?
    C: RCPT TO:<bob@example.org>
    S: 250 2.1.5 recipient ok
    C: RCPT TO:<carol@example.org>
    S: 550 5.1.1 no such user here
       [carol: 5xx permanent: drop, bounce (NDR) to alice]
    ...
    S: 250 2.0.0 queued for bob
    C: QUIT
    S: 221 2.0.0 bye   (server stored: ["Subject: test","","Hi Bob,",".hidden starts with a dot","-- Alice"])

    greylist বন্ধ, তাই bob প্রথমবারেই 250; bob-এর জন্য কোনো 4xx নোট নেই। carol আগের মতোই স্থায়ী ব্যর্থতা। একটি প্রাপক গৃহীত, তাই DATA পাঠানো হয়, dot-stuffing হয়, আর সার্ভার আসল লেখা জমা রাখে। লুপ একবারই চলে, তাই “t=30” অংশটি আর ছাপা হয় না।

  4. DNS record লিখুন: example.com-এর চিঠি গ্রহণ করবে দুটি সার্ভার — mx1.example.com (প্রধান) আর mx2.example.com (ব্যাকআপ)। চিঠি পাঠায় অফিসের সার্ভার 192.0.2.10 আর একটি নিউজলেটার সেবা, যার SPF _spf.example.net-এ। DKIM selector “s1”. DMARC শুরু করতে চান শুধু পর্যবেক্ষণে, রিপোর্ট যাবে dmarc@example.com-এ। MX, SPF, DKIM-এর নাম আর DMARC record লিখুন।
    example.com.                 MX   10 mx1.example.com.
    example.com.                 MX   20 mx2.example.com.
    example.com.                 TXT  "v=spf1 ip4:192.0.2.10 include:_spf.example.net ~all"
    s1._domainkey.example.com.   TXT  "v=DKIM1; k=rsa; p=<public key, base64>"
    _dmarc.example.com.          TXT  "v=DMARC1; p=none; rua=mailto:dmarc@example.com"

    ব্যাকআপের preference বড় (২০)। SPF-এ একটিমাত্র record; শুরুতে ~all নিরাপদ, সব প্রেরক নিশ্চিত হলে -all. DKIM-এর গোপন key থাকে পাঠানো সার্ভারে, DNS-এ শুধু public key. DMARC p=none চিঠির ভাগ্য বদলায় না, শুধু রিপোর্ট আনে; কয়েক সপ্তাহ রিপোর্ট দেখে সব বৈধ উৎস aligned হলে p=quarantine, তারপর p=reject. নিউজলেটার সেবাকে নিজের ডোমেইনের DKIM দিয়ে সই করাতে হবে, নইলে তার চিঠি alignment পাবে না।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমএকটি SMTP সংযোগে একটি চিঠি পাঠানোর ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. সার্ভার 220 দিয়ে অভিবাদন জানায়
  2. ক্লায়েন্ট EHLO পাঠায়, সার্ভার 250-এ নিজের ক্ষমতার তালিকা দেয়
  3. ক্লায়েন্ট MAIL FROM দিয়ে envelope-এর প্রেরক জানায়
  4. ক্লায়েন্ট প্রতিটি প্রাপকের জন্য RCPT TO পাঠায়
  5. DATA → 354, তারপর header, ফাঁকা লাইন, body আর একক “.”, উত্তরে 250
  6. ক্লায়েন্ট QUIT পাঠায়, সার্ভার 221 দিয়ে সংযোগ বন্ধ করে

example.org-এর MX record দুটি: MX 20 mx-a.example.org আর MX 10 mx-b.example.org. দুটিই চালু থাকলে একটি প্রেরক MTA প্রথমে কোনটিতে চিঠি পাঠাবে?

  • mx-a, কারণ তালিকায় সেটি আগে লেখা
  • mx-b, কারণ তার preference সংখ্যা ছোট
  • mx-a, কারণ তার preference সংখ্যা বড়
  • দুটির মধ্যে এলোমেলোভাবে যেকোনো একটি

একটি MTA RCPT TO:<rahim@example.org>-এর উত্তরে পেল 451 4.7.1 try again later. সঠিক আচরণ কোনটি?

  • সাথে সাথে প্রেরককে bounce পাঠিয়ে চিঠি বাতিল করা
  • একই সংযোগে সাথে সাথে বারবার একই RCPT পাঠানো
  • চিঠি queue-তে রেখে কিছুক্ষণ পরে আবার চেষ্টা করা
  • প্রাপকের ঠিকানা বদলে অন্য MX-এ পাঠানো

একটি email অ্যাপ (MUA) নিজের সরবরাহকারীর সার্ভারে নতুন চিঠি জমা দিচ্ছে, সংযোগ শুরু হবে সাধারণ লেখায় আর তারপর STARTTLS ও পাসওয়ার্ড-যাচাই। কোন TCP port সবচেয়ে উপযুক্ত?

  • 587
  • 25
  • 993
  • 465

একটি চিঠির envelope-এ MAIL FROM:<news@example.net> আর header-এ From: info@example.com. প্রাপক SPF যাচাই করবে কোন ডোমেইনের record দিয়ে?

  • example.com, কারণ পাঠক From:-এ সেটিই দেখেন
  • দুটোরই, আর দুটো pass হলে তবে pass
  • প্রাপকের নিজের ডোমেইনের
  • example.net, কারণ SPF খামের MAIL FROM দেখে

example.com-এর DMARC নীতি p=reject. একটি চিঠিতে From: example.com, SPF fail (forward হওয়ায় নতুন IP), আর DKIM pass যার d=example.com. DMARC-এর ফল কী?

  • fail, কারণ SPF ব্যর্থ
  • pass, কারণ DKIM pass আর তার ডোমেইন From:-এর সাথে aligned
  • quarantine, কারণ ফল মিশ্র
  • নির্ধারণ করা যায় না

একটি চিঠির body-তে একটি লাইন হুবহু .config saved. SMTP-র DATA ধাপে এই লাইনটি তারে কী আকারে যাবে?

  • .config saved
  • config saved
  • ..config saved
  • পুরো লাইন base64-এ

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. MUA → MSA (587/465, AUTH) → MTA → MX (25) → MDA/mailbox → IMAP/POP3: পাঠানো push (SMTP), পড়া pull. কোন সার্ভারে যাবে তা বলে DNS-এর MX — ছোট preference আগে।
  2. SMTP কথোপকথন: 220, EHLO/250, MAIL FROM, RCPT TO, DATA/354, বার্তা, একক “.”/250, QUIT/221. 2xx সফল, 3xx আরও দিন, 4xx সাময়িক (queue, retry), 5xx স্থায়ী (bounce). বিন্দু-দিয়ে-শুরু লাইনে dot-stuffing.
  3. Envelope ≠ header: MTA খাম (MAIL FROM/RCPT TO) দেখে, পাঠক From:/To: দেখেন — BCC আর spoofing দুটোই এখান থেকে। Received header নিচ থেকে ওপরে পড়ুন।
  4. MIME: Content-Type (multipart/alternative, multipart/mixed, boundary), base64 (৩ বাইট → ৪ অক্ষর, ৭৬ অক্ষরের লাইন), quoted-printable, আর header-এ =?UTF-8?B?…?=.
  5. SPF (খামের ডোমেইনের IP তালিকা, ১০-lookup সীমা) + DKIM (সই, selector._domainkey) + DMARC (aligned pass, none/quarantine/reject, রিপোর্ট); পথের জন্য MTA-STS/DANE, গোপনীয়তার জন্য PGP/S/MIME.

পরের পর্বে: ইমেইল মিনিট বা ঘণ্টা অপেক্ষা করতে পারে, কিন্তু ভিডিও কল পারে না। Real-time আর streaming — WebSocket, VoIP আর ভিডিও স্ট্রিমিং: দেরি, jitter আর packet হারানোর সাথে কীভাবে লড়তে হয়।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান