Mundarija (26)
- Bu darsda
- 1. Nega bu kerak?
- 2. Uch yozuv
- 2.1 DNS'dagi TXT yozuvlar
- 2.2 SPF: yuborgan IP ro'yxatdami
- 2.3 DKIM: xatdagi muhr
- 2.4 DMARC: From: bilan moslik
- 3. Kanon tajribasi: sakkiz holat
- 3.1 Natijalar
- 3.2 rDNS va HELO
- 4. Obro', bounce va shikoyatlar
- 4.1 Tranzaksion va marketing xatlar
- 4.2 Google va Yahoo talablari
- 4.3 One-click obunadan chiqish
- 4.4 Bounce va shikoyat
- 5. Provayder tanlash
- 6. Hujumchi nigohi
- 7. Ko'p uchraydigan xatolar
- 8. Mashqlar
- 1-mashq (oson): qaysi tekshiruv?
- 2-mashq (o'rta): DMARC moslik
- 3-mashq (qiyin): include va 10 so'rov chegarasi
- 9. Loyiha qadami: tajriba, modulga yangi kod yo'q
- 10. Real ishda
- Xulosa
- Manbalar
Email deliverability: SPF, DKIM, DMARC va xat nega spam'ga tushadi
Qisqacha: Xat yuborildi — bu hali qutiga tushdi degani emas. Qabul qiluvchi server uch narsani tekshiradi: SPF (yuborgan IP domen ro'yxatidami), DKIM (xat yo'lda o'zgarmaganini isbotlovchi imzo) va DMARC (
From:domeni shu tekshiruvlardan biriga mos va o'tganmi, o'tmasa nima qilish). Uchalasi domenning DNS'idagi TXT yozuvlar. Ulardan tashqari obro' muhim: bounce va shikoyatlarni kuzating, marketing xatlarda bir bosishda obunadan chiqish (List-Unsubscribeone-click) bering.
Bu darsda
- SPF, DKIM va DMARC nimani tekshirishini va DNS'da qanday yozilishini tushuntirasiz.
- Kanon tajribasidagi sakkiz holatni (forward, o'zgartirilgan xat, soxta yuboruvchi) o'qiy olasiz.
- SPF tekshiruvi va DMARC moslik (alignment) qoidasini o'zingiz yozasiz.
- One-click obunadan chiqish endpoint'ini yozasiz.
- Bounce, shikoyat va provayderlar haqida qaror qabul qila olasiz.
Oldin bilishingiz kerak: Domen va DNS, crypto: hash, shifrlash va imzo (RSA imzo), Email yuborish: SMTP va Nodemailer, Email shablonlarini serverda render qilish.
Oldingi ikki darsda xatni yig'dik va yubordik. Mailpit'da hammasi chiroyli edi. Haqiqiy dunyoda esa Aziz shikoyat qiladi: "Tasdiqlash xati kelmadi". Xat Spam papkasida yotibdi.
1. Nega bu kerak?
Email 1980-yillarda ishonch asosida loyihalangan: SMTP'da From: ga istalgan manzilni yozish mumkin. Buni o'tgan darsdagi SMTP dialogida ko'rdingiz — MAIL FROM ni hech kim tekshirmadi. Firibgar From: bank@kapitalbank.uz deb yozib, "kartangiz bloklandi" xatini yuboradi.
Qabul qiluvchi serverlar (Gmail, Outlook, Mail.ru) bu bilan kurashadi: har xatni tekshiradi va baho beradi. Baho past bo'lsa — spam yoki umuman rad. Sizning to'g'ri xatingiz ham shu tekshiruvdan o'tadi.
O'xshatish: muhim hujjat notarius orqali yuboriladi. SPF — "bu xatni shu pochta bo'limidan yuborish mumkin" degan ro'yxat. DKIM — hujjatdagi muhr: yo'lda kimdir bir harfni o'zgartirsa, muhr buziladi. DMARC — "muhr yoki bo'lim tekshiruvdan o'tmasa, hujjatni yoqib yuboring" degan ko'rsatma. Uchalasini domen egasi e'lon qiladi, qabul qiluvchi faqat o'qiydi.
2. Uch yozuv
2.1 DNS'dagi TXT yozuvlar
Kanon vazifalar.example.uz domeni uchun to'rtta yozuv tuzdi (example — o'quv domeni, IP'lar — hujjatlar uchun ajratilgan RFC 5737 diapazonlari):
DNS yozuvlari (domen panelida qo'yiladi):
s1._domainkey.vazifalar.example.uz TXT v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvSMIRNP3RKu6UA8pk/VHdLaeLysZ…
vazifalar.example.uz TXT v=spf1 ip4:192.0.2.10 include:_spf.provayder.example -all
_spf.provayder.example TXT v=spf1 ip4:198.51.100.0/24 -all
_dmarc.vazifalar.example.uz TXT v=DMARC1; p=reject; rua=mailto:dmarc@vazifalar.example.uz; adkim=s; aspf=r; pct=100| Yozuv | Joyi | Ma'nosi |
|---|---|---|
| SPF | domenning o'zi | 192.0.2.10 va provayder tarmog'i yubora oladi, qolganlar — yo'q (-all) |
| DKIM | s1._domainkey.<domen> |
s1 selektorli ochiq kalit (RSA 2048) |
| DMARC | _dmarc.<domen> |
o'tmasa — rad (p=reject), hisobotlar rua ga |
Haqiqiy domen va haqiqiy DNS kanonda sinalmagan. DNS javoblari tajriba skriptidagi jadvaldan berildi. Lekin imzolash (Nodemailer) va tekshiruv (mailauth 8.0.1 — haqiqiy pochta serverlari ishlatadigan kod) — haqiqiy.
2.2 SPF: yuborgan IP ro'yxatdami
SPF (Sender Policy Framework) — domen nomidan xat yuborishga ruxsat berilgan IP'lar ro'yxati. Qabul qiluvchi server ulanayotgan IP'ni oladi, konvertdagi MAIL FROM domenining SPF yozuvini o'qiydi va solishtiradi. Mexanizmlar chapdan o'ngga tekshiriladi, birinchi mos kelgani hal qiladi:
ip4:192.0.2.10yokiip4:198.51.100.0/24— bitta IP yoki tarmoq (IP manzil va port).include:boshqa.domen— o'sha domenning SPF'ini ham tekshir (provayderingiz ro'yxati).-all— qolgan hammasifail;~all—softfail(shubhali, lekin rad emas).
Asosiy qismni o'zimiz yozamiz:
const NATIJA = {
"+": "pass", "-": "fail", "~": "softfail", "?": "neutral",
};
const songa = (ip) =>
ip.split(".").reduce((a, q) => a * 256 + Number(q), 0);
function ichidami(ip, cidr) {
const [tarmoq, uz = "32"] = cidr.split("/");
const bloklar = 2 ** (32 - Number(uz));
const bosh = Math.floor(songa(tarmoq) / bloklar) * bloklar;
const x = songa(ip);
return x >= bosh && x < bosh + bloklar;
}
function spfBahola(yozuv, ip) {
for (const q of yozuv.split(" ").slice(1)) {
const belgi = "+-~?".includes(q[0]) ? q[0] : "+";
const mexanizm = belgi === q[0] ? q.slice(1) : q;
const ip4 = mexanizm.startsWith("ip4:")
&& ichidami(ip, mexanizm.slice(4));
const mos = mexanizm === "all" || ip4;
if (mos) return NATIJA[belgi];
}
return "neutral";
}
const spf = "v=spf1 ip4:192.0.2.10 ip4:198.51.100.0/24 -all";
console.log(ichidami("198.51.100.25", "198.51.100.0/24"));
console.log(spfBahola(spf, "192.0.2.10"));
console.log(spfBahola(spf, "198.51.100.25"));
console.log(spfBahola(spf, "203.0.113.9"));
console.log(spfBahola("v=spf1 ip4:192.0.2.10 ~all", "203.0.113.9"));Konsolda:
true
pass
pass
fail
softfailsonga— IP'ni bitta songa aylantiradi (to'rt bayt, 256 lik sanoq)./24— oxirgi 8 bit erkin: 256 manzil.bosh— tarmoqning birinchi manzili.- Prefiks bo'lmasa (
ip4:192.0.2.10), mexanizm+hisoblanadi.
SPF'ning zaif joyi: u konvert domenini tekshiradi, Aziz ko'radigan From: ni emas. Firibgar konvertga o'z domenini, From: ga esa bankni yozsa — SPF uning domeni bo'yicha pass beradi. Bu teshikni DMARC yopadi.
2.3 DKIM: xatdagi muhr
DKIM (DomainKeys Identified Mail) — xatning sarlavhalari va tanasi ustidan raqamli imzo. Yuboruvchi server yopiq kalit bilan imzolaydi va xatga DKIM-Signature sarlavhasini qo'shadi. Qabul qiluvchi d= (domen) va s= (selektor) bo'yicha DNS'dan ochiq kalitni olib, imzoni tekshiradi (crypto: imzo). Kanon imzosining boshi:
DKIM-Signature: DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;…Nodemailer'da bu bitta sozlama — Pochta modulidagi dkim:
import { generateKeyPairSync } from "node:crypto";
// bir marta: kalit juftligi; yopiq — .env ga, ochiq — DNS ga
const { privateKey, publicKey } = generateKeyPairSync("rsa", {
modulusLength: 2048,
});
const dnsQiymat = publicKey
.export({ type: "spki", format: "der" })
.toString("base64"); // TXT: v=DKIM1; k=rsa; p=<dnsQiymat>
const transporter = nodemailer.createTransport({
host, port, secure, auth,
dkim: {
domainName: "vazifalar.example.uz",
keySelector: "s1",
privateKey: process.env.DKIM_YOPIQ_KALIT,
},
});Amalda provayder (SES, Postmark, Resend) DKIM'ni o'zi qo'yadi: u sizga 2–3 ta DNS yozuvini beradi, kalit esa uning serverida. O'zingiz imzolash — o'z SMTP serveringiz bo'lsa kerak. Selektor kalitni almashtirishga yordam beradi: yangi kalit s2 ga qo'yiladi, eski s1 bir muddat qoladi, keyin o'chiriladi.
2.4 DMARC: From: bilan moslik
DMARC (Domain-based Message Authentication, Reporting and Conformance) ikki ish qiladi:
- Moslik (alignment): SPF yoki DKIM
passbo'lishi yetmaydi. Tekshirilgan domen Aziz ko'radiganFrom:domeni bilan mos bo'lishi kerak.aspf=r— SPF uchun yumshoq (relaxed) moslik: bir tashkilot domeni yetarli (bounce.example.uzvavazifalar.example.uz).adkim=s— DKIM uchun qat'iy (strict): domenlar aynan bir xil. - Siyosat: ikkalasi ham o'tmasa nima qilish —
p=none(faqat hisobot),p=quarantine(spam),p=reject(rad).
rua — qabul qiluvchilar har kuni yuboradigan yig'ma hisobotlar manzili: kim sizning domeningizdan xat yubordi va natijasi qanday.
flowchart TD
X[Xat keldi] --> S{SPF pass va From ga mos?}
S -->|ha| P[DMARC pass]
S -->|yo'q| D{DKIM pass va From ga mos?}
D -->|ha| P
D -->|yo'q| F[DMARC fail]
F --> Q{p= siyosati}
Q -->|none| N[qabul, hisobot]
Q -->|quarantine| SP[Spam]
Q -->|reject| R[Rad etish]Diagrammaga qarang: DMARC uchun bittasi yetarli — SPF yoki DKIM. Bu keyingi bo'limdagi forward holatini tushuntiradi.
3. Kanon tajribasi: sakkiz holat
3.1 Natijalar
Kanon bitta imzolangan xatni turli sharoitda tekshirdi. Har qatorning oxirgi ustuniga — DMARC natijasiga qarang: xatning taqdirini aynan u hal qiladi:
to'g'ri: DKIM + SPF (o'z IP) DKIM pass | SPF pass | DMARC pass (p=reject)
provayder IP'si (include:) DKIM pass | SPF pass | DMARC pass (p=reject)
begona IP, DKIM bor (forward kabi) DKIM pass | SPF fail | DMARC pass (p=reject)
imzosiz, begona IP (soxta yuboruvchi) DKIM none (message not signed) | SPF fail | DMARC fail (p=reject)
imzodan keyin mavzu o'zgartirildi DKIM fail (bad signature) | SPF pass | DMARC pass (p=reject)
tana o'zgartirildi (ro'yxat footer qo'shdi) DKIM neutral (body hash did not verify) | SPF pass | DMARC pass (p=reject)
boshqa kalit bilan imzolangan DKIM fail (bad signature) | SPF pass | DMARC pass (p=reject)
From: boshqa domen, DKIM bizniki (aligned emas) DKIM pass | SPF pass | DMARC noneQatorma-qator:
- To'g'ri — hammasi
pass. - Provayder IP'si —
include:ishladi. - Forward — Aziz xatlarini boshqa qutiga yo'naltirgan. Endi xatni boshqa server, boshqa IP'dan uzatadi: SPF
fail. Lekin DKIM imzosi xat bilan birga keldi —pass. DMARC'ga bittasi yetarli —pass. DKIM — forward'dan omon qoladigan yagona tekshiruv. - Soxta yuboruvchi — imzo yo'q, IP begona: DMARC
fail,p=reject— xat rad etiladi. Firibgar to'xtadi. - Mavzu o'zgartirildi — "bad signature": imzolangan sarlavha o'zgardi. SPF hali
passbo'lgani uchun DMARC o'tdi. - Tana o'zgartirildi — "body hash did not verify". Pochta ro'yxatlari (mailing list) xat oxiriga futer qo'shganda shunday bo'ladi.
- Begona kalit — imzo bor, lekin DNS'dagi ochiq kalitga mos emas.
From:boshqa domen — DKIM va SPF biznikidapass, lekinFrom: bank@bank.example. DMARCbank.examplening yozuvini qidirdi — yo'q, natijanone. Agar bankning DMARC'ip=rejectbo'lganda, xat rad etilardi: imzo bizniki,From:esa bankniki — moslik yo'q.
5- va 6-qatorlarga yana qarang: DKIM buzilgan, lekin xat SPF tufayli o'tdi. Xat forward qilinib, yo'lda o'zgartirilsa — ikkalasi ham yiqiladi. Shuning uchun ikkalasini sozlang: biri tushsa, ikkinchisi ushlaydi.
Tekshirib ko'ring: Kompaniya DMARC'ni darhol
p=rejectbilan yoqdi. Ertasiga buxgalteriya xatlari mijozlarga yetmay qoldi. Nima bo'lgan bo'lishi mumkin?
Javob
Buxgalteriya xatlarni boshqa xizmat (masalan, hisob-faktura dasturi) orqali yuborar edi. Uning IP'si SPF'da yo'q, DKIM imzosi kompaniya domeni bilan emas. DMARC fail, p=reject — rad. Shuning uchun DMARC bosqichma-bosqich yoqiladi: avval p=none va rua hisobotlari — kim domeningizdan yuborayotganini ko'rasiz, hammasini SPF/DKIM'ga qo'shasiz, keyin quarantine, oxirida reject.
3.2 rDNS va HELO
Yana ikki tekshiruv o'z serverdan yuborganda muhim (kanonda sinalmagan, hujjat bo'yicha):
- rDNS (teskari DNS, PTR yozuvi):
192.0.2.10IP'si qaysi nomga tegishli. Umail.vazifalar.example.uzga, o'sha nom esa yana shu IP'ga ko'rsatsin. PTR'ni domen paneli emas, IP egasi (hosting) qo'yadi. - HELO/EHLO nomi — server o'zini tanishtirgan nom; u ham haqiqiy, DNS'da bor nom bo'lsin.
Provayder orqali yuborganda bu ikkalasi provayderning ishi.
4. Obro', bounce va shikoyatlar
4.1 Tranzaksion va marketing xatlar
Autentifikatsiya — eshikdan kirish. Qutiga tushish esa obro'ga (reputation) bog'liq: domeningiz va IP'ingizdan kelgan xatlar qanchalik ko'p ochiladi, spam deb belgilanadi, mavjud bo'lmagan manzillarga ketadi.
Ikki turdagi xatni ajrating:
| Tranzaksion | Marketing | |
|---|---|---|
| Misol | tasdiqlash, parol, eslatma | yangiliklar, aksiya |
| Kim boshlaydi | foydalanuvchi harakati | siz |
| Obunadan chiqish | shart emas (tasdiqlash xatida) | majburiy, bir bosishda |
| Yuborish yo'li | alohida oqim yoki subdomen | alohida oqim yoki subdomen |
Ularni ajratishning sababi: marketing xati spam deb belgilansa, uning obro'si tushadi. Bitta domen va IP bo'lsa, parol tiklash xati ham spam'ga tusha boshlaydi. Provayderlar buni "stream" yoki alohida subdomen (news.vazifalar.example.uz) bilan hal qiladi.
4.2 Google va Yahoo talablari
2024-yil 1-fevraldan Gmail va Yahoo ommaviy yuboruvchilardan (bulk sender) qo'shimcha talab qiladi. Google qo'llanmasida bu — Gmail manzillariga kuniga 5 000 dan ortiq xat yuboradigan. Talablar (ikkala hujjat, 2026-10-28 holati):
| Talab | Yahoo | |
|---|---|---|
| SPF va DKIM | ikkalasi ham | ikkalasi ham |
| DMARC | kamida p=none |
kamida p=none, DMARC pass bo'lsin |
| One-click obunadan chiqish (RFC 8058) | marketing va obuna xatlarida | marketing va obuna xatlarida |
| Spam shikoyatlari ulushi | 0.10 % dan past tuting, hech qachon 0.30 % ga yetmasin | 0.3 % dan past |
DMARC'ni p=none bilan boshlashga ruxsat bor — bu «Tekshirib ko'ring» savolidagi bosqichma-bosqich yo'lga mos. Talablar o'zgarishi mumkin — joriy holatni manbalardagi havoladan tekshiring.
4.3 One-click obunadan chiqish
Pochta.yubor() obunaBekor berilganda ikki sarlavha qo'shadi. Biz modulni lokal SMTP serverga ulab, xom xatni ko'rdik (nodemailer 10.1.7):
List-Unsubscribe-Post: List-Unsubscribe=One-Click
List-Unsubscribe: <https://vazifalar.example.uz/obuna/x1> (Obunani bekor
qilish)List-Unsubscribe (RFC 2369) — obunadan chiqish manzili; Gmail uni xat tepasida "Unsubscribe" tugmasi qilib ko'rsatadi. Ikkinchi qatordagi bo'shliq bilan boshlangan davom — sarlavhani bo'lish (folding): uzun sarlavha bir necha qatorga yoyiladi. List-Unsubscribe-Post (RFC 8058) — "bu havolaga POST yuborilsa, hech qanday sahifasiz obuna bekor bo'ladi".
Server tomoni — bitta POST marshruti. Toza node:http bilan:
import { createServer } from "node:http";
const obunalar = new Map([
["x1", { email: "aziz@example.uz", faol: true }],
]);
const server = createServer(async (req, res) => {
const m = req.url.match(/^\/obuna\/(\w+)$/);
const obuna = m && obunalar.get(m[1]);
if (req.method !== "POST" || !obuna) {
res.writeHead(404).end();
return;
}
let tana = "";
for await (const b of req) tana += b;
if (tana !== "List-Unsubscribe=One-Click") {
res.writeHead(400).end();
return;
}
obuna.faol = false;
res.writeHead(200).end("bekor qilindi");
});
await new Promise((r) => server.listen(0, "127.0.0.1", r));
const url = `http://127.0.0.1:${server.address().port}/obuna/x1`;
const r1 = await fetch(url, {
method: "POST",
headers: { "content-type": "application/x-www-form-urlencoded" },
body: "List-Unsubscribe=One-Click",
});
console.log(r1.status, await r1.text(), obunalar.get("x1"));
const r2 = await fetch(url);
console.log("GET:", r2.status, obunalar.get("x1").faol);
server.closeAllConnections();
server.close();Konsolda:
200 bekor qilindi { email: 'aziz@example.uz', faol: false }
GET: 404 falseNega GET ga javob yo'q? Antivirus va korporativ pochta filtrlari xatdagi havolalarni oldindan ochib tekshiradi. GET obunani bekor qilsa, foydalanuvchi hech narsa bosmasdan obunadan chiqib qoladi. RFC 8058 aynan shuning uchun POST talab qiladi. x1 — taxmin qilib bo'lmaydigan token bo'lsin: ketma-ket ID (/obuna/42) bilan hujumchi hammaning obunasini bekor qiladi. Prodda obunalar — baza, token esa Bildirishnoma tizimi darsidagi foydalanuvchi afzalliklariga bog'lanadi.
4.4 Bounce va shikoyat
- Hard bounce — doimiy rad (
550, "bunday quti yo'q"). Manzil darhol bostirish ro'yxatiga (suppression list) tushadi — unga boshqa yuborilmaydi. - Soft bounce — vaqtinchalik (
4xx, quti to'la). Bir necha marta qayta urinib, keyin to'xtatiladi. - Shikoyat (complaint) — foydalanuvchi "Spam" tugmasini bosdi. Darhol bostirish ro'yxatiga.
Provayderlar bu hodisalarni sizga webhook bilan yuboradi — o'z serveringizdagi URL'ga HTTP POST (Kiruvchi webhook'larni qabul qilish darsida chuqur). Amazon SES — SNS orqali, Postmark va Resend — to'g'ridan. Bu webhook'lar kanonda sinalmagan (provayder hisobi kerak) — formatlari hujjatlarda.
O'lik manzillarga yuborishda davom etish — obro'ni eng tez tushiradigan xato. Ro'yxatdan o'tishda emailni tasdiqlash (28-qismda) — ham xavfsizlik, ham obro' uchun.
5. Provayder tanlash
Kanon hech bir provayderni sinamagan. Tanlashda qaraladigan narsalar:
| Mezon | Nimaga qarash |
|---|---|
| Autentifikatsiya | DKIM, SPF (include), custom return-path |
| Webhook | bounce, complaint, delivery hodisalari |
| Oqimlar | tranzaksion va marketing ajratilganmi |
| Narx va limit | bepul daraja, soniyadagi xat |
Keng tarqalganlari: Amazon SES (arzon, sozlash ko'proq) va Postmark (tranzaksion xatlarga ixtisoslashgan). Yana Resend (dasturchilar uchun, React Email bilan bir jamoa) va Brevo (marketing va tranzaksion). Pochta moduli SMTP orqali ishlagani uchun ulardan istalganiga faqat .env o'zgaradi.
6. Hujumchi nigohi
| Hujum | Himoya |
|---|---|
| sizning domeningizdan soxta xat (spoofing) | SPF + DKIM + DMARC p=reject — kanonda 4-holat rad |
o'xshash domen (vazifa1ar.uz) |
DMARC yordam bermaydi; foydalanuvchini o'rgatish, brend monitoringi |
| DKIM yopiq kaliti sizdi | kalit .env da; yangi selektor bilan almashtirish |
| ketma-ket obuna tokeni | tasodifiy token |
GET bilan obunadan chiqarish |
faqat POST (RFC 8058) |
Birinchi qator — DMARC'siz domen firibgarlar uchun ochiq eshik. Hatto domen umuman xat yubormasa ham, unga v=spf1 -all va p=reject qo'yish tavsiya etiladi — aks holda uning nomidan bemalol yuborishadi.
7. Ko'p uchraydigan xatolar
| Xato | Natija | To'g'risi |
|---|---|---|
| ikkita SPF yozuvi | SPF permerror |
bitta yozuv, ichida bir nechta mexanizm |
include juda ko'p |
10 ta DNS so'rov chegarasi | keraksizlarini olib tashlash |
darhol p=reject |
o'z xatlaringiz rad | none → quarantine → reject |
| faqat SPF | forward'da yiqiladi | DKIM ham |
From: va DKIM domeni boshqa |
DMARC moslik yo'q | d= = From: domeni |
| bounce'larni e'tiborsiz qoldirish | obro' tushadi | bostirish ro'yxati |
| marketing va tranzaksion bitta oqimda | parol xati spam'ga | alohida oqim/subdomen |
8. Mashqlar
Mashqlar kurs/mashqlar/29/15-deliverability/ da.
1-mashq (oson): qaysi tekshiruv?
Har holat uchun qaysi tekshiruv yiqilishini yozing (SPF, DKIM yoki hech biri):
- Xat forward qilindi, mazmuni o'zgarmadi.
- Pochta ro'yxati xat oxiriga reklama qo'shdi, o'z serveridan uzatdi.
- Provayder IP'si
include:da bor. - Firibgar o'z serveridan imzosiz yubordi.
Yechim
- SPF — IP o'zgardi; DKIM omon qoldi (kanon: DMARC pass).
- SPF va DKIM — IP ham, tana ham o'zgardi; DMARC
fail. Shuning uchun pochta ro'yxatlari ARC (Authenticated Received Chain — "xat menga kelganda tekshiruvlardan o'tgan edi" degan oraliq server imzosi) kabi qo'shimcha mexanizmlar ishlatadi. - Hech biri —
includeprovayder tarmog'ini qamraydi. - SPF va DKIM — kanon:
DKIM none,SPF fail,DMARC fail→ rad.
2-mashq (o'rta): DMARC moslik
mosmi(fromDomen, tekshirilganDomen, rejim) funksiyasini yozing: rejim === "s" — domenlar aynan bir xil (katta-kichik harf farqsiz); "r" — tashkilot domeni bir xil (soddalashtirilgan: oxirgi ikki qism, vazifalar.example.uz → example.uz). Ishora: split("."), slice(-2), join(".").
Yechim
const tashkilot = (domen) =>
domen.toLowerCase().split(".").slice(-2).join(".");
function mosmi(fromDomen, tekshirilgan, rejim) {
if (rejim === "s") {
return fromDomen.toLowerCase() === tekshirilgan.toLowerCase();
}
return tashkilot(fromDomen) === tashkilot(tekshirilgan);
}
const FROM = "vazifalar.example.uz";
console.log(mosmi(FROM, "vazifalar.example.uz", "s"));
console.log(mosmi(FROM, "bounce.example.uz", "s"));
console.log(mosmi(FROM, "bounce.example.uz", "r"));
console.log(mosmi(FROM, "Vazifalar.Example.UZ", "s"));
console.log(mosmi(FROM, "provayder.example", "r"));Konsolda:
true
false
true
true
falseUchinchi qator — provayderlar aynan shunga tayanadi: konvert manzili bounce.example.uz, From: esa vazifalar.example.uz. Yumshoq rejimda SPF mos. Oxirgi qator: provayder domenidagi SPF pass bizning From: ga yordam bermaydi. "Oxirgi ikki qism" — soddalashtirish: co.uk kabi domenlarda u xato. Haqiqiy kutubxonalar Public Suffix List ro'yxatidan foydalanadi.
3-mashq (qiyin): include va 10 so'rov chegarasi
Darsdagi spfBahola ni spf(domen, ip) ga aylantiring: yozuv DNS obyektidan olinadi (yo'q bo'lsa — "none"), include: boshqa domenni rekursiv tekshiradi (ichki natija pass bo'lsa — mos). Har include hisoblanadi, 10 dan oshsa — "permerror". O'zini o'zi include qiladigan yozuv bilan sinang. Ishora: hisoblagichni obyekt sifatida uzating — rekursiv chaqiruvlar uni bo'lishadi (Rekursiya asoslari).
Yechim
const DNS = {
"vazifalar.example.uz":
"v=spf1 ip4:192.0.2.10 include:_spf.prov.example -all",
"_spf.prov.example": "v=spf1 ip4:198.51.100.0/24 -all",
"halqa.example": "v=spf1 include:halqa.example -all",
};
const NATIJA = {
"+": "pass", "-": "fail", "~": "softfail", "?": "neutral",
};
const songa = (ip) =>
ip.split(".").reduce((a, q) => a * 256 + Number(q), 0);
function ichidami(ip, cidr) {
const [tarmoq, uz = "32"] = cidr.split("/");
const bloklar = 2 ** (32 - Number(uz));
const bosh = Math.floor(songa(tarmoq) / bloklar) * bloklar;
return songa(ip) >= bosh && songa(ip) < bosh + bloklar;
}
function spf(domen, ip, hisob = { soni: 0 }) {
const yozuv = DNS[domen];
if (!yozuv) return "none";
for (const q of yozuv.split(" ").slice(1)) {
const belgi = "+-~?".includes(q[0]) ? q[0] : "+";
const mex = belgi === q[0] ? q.slice(1) : q;
let mos = mex === "all";
if (mex.startsWith("ip4:")) mos = ichidami(ip, mex.slice(4));
if (mex.startsWith("include:")) {
hisob.soni++;
if (hisob.soni > 10) return "permerror";
const ichki = spf(mex.slice(8), ip, hisob);
if (ichki === "permerror") return ichki;
mos = ichki === "pass";
}
if (mos) return NATIJA[belgi];
}
return "neutral";
}
console.log(spf("vazifalar.example.uz", "192.0.2.10"));
console.log(spf("vazifalar.example.uz", "198.51.100.25"));
console.log(spf("vazifalar.example.uz", "203.0.113.9"));
console.log(spf("yoq.example", "192.0.2.10"));
console.log(spf("halqa.example", "192.0.2.10"));Konsolda:
pass
pass
fail
none
permerrorhalqa.example o'zini o'zi chaqiradi — chegarasiz rekursiya stekni to'ldirardi (Rekursiya asoslari). Haqiqiy SPF standarti (RFC 7208) ham aynan 10 ta DNS so'rov chegarasini qo'yadi — hujumchi bitta xat bilan qabul qiluvchi serverni minglab DNS so'roviga majburlamasin. Shu sababli bir nechta provayderni include qilgan kompaniyalar bu chegaraga tez-tez uriladi.
9. Loyiha qadami: tajriba, modulga yangi kod yo'q
Bu dars Pochta moduliga yangi kod qo'shmaydi — kerakli ikki imkoniyat avvaldan bor:
dkimsozlamasi — o'z SMTP serveri bilan imzolash uchun; provayder orqali yuborilsa, berilmaydi.obunaBekor→List-UnsubscribevaList-Unsubscribe-Post. Kanon testi (Mailpit orqali) sarlavhalarni aynan tekshiradi (qatorlarni telefon uchun bo'ldik):
const h = await sarlavhalar(x.ID);
assert.deepEqual(h["List-Unsubscribe"],
["<https://v.example/obuna/xyz> (Obunani bekor qilish)"]);
assert.deepEqual(h["List-Unsubscribe-Post"],
["List-Unsubscribe=One-Click"]);SPF, DKIM, DMARC tekshiruvi esa domen va DNS bilan bog'liq — u kodda emas, domen panelida. Kanon uni tajribada (mailauth bilan) ko'rsatdi va loyihaga kiritmadi: haqiqiy domen va provayder yo'q.
vazifalar-api da one-click marshruti 28-qism tugagach qo'shiladi: u foydalanuvchining email bildirishnomalari afzalligini o'chiradi.
10. Real ishda
- Deploy ro'yxati: yangi domen ochilganda SPF, DKIM (provayder bergan yozuvlar) va DMARC
p=none+rua— birinchi kunning ishi. Hisobotlarni o'qish uchun DMARC tahlil xizmatlari bor. - Pochta testerlari (mail-tester, Gmail'dagi "Show original") xatning SPF, DKIM, DMARC natijalarini ko'rsatadi.
- Kompaniyalarda DMARC'ni
rejectgacha olib borish — xavfsizlik jamoasining alohida loyihasi. - Intervyuda: "SPF, DKIM, DMARC farqi?", "Forward qilingan xat nega o'tadi?", "Xatlarimiz spam'ga tushyapti — qayerdan boshlaysiz?"
Xulosa
- SPF — konvert domeni uchun ruxsat etilgan IP'lar; forward'da yiqiladi.
- DKIM — sarlavha va tana imzosi; yo'lda o'zgarsa
fail, forward'dan omon qoladi. - DMARC —
From:ga mos SPF yoki DKIMpass; siyosatnone→quarantine→reject. - Kanon: soxta yuboruvchi
p=rejectbilan rad; forward — DKIM tufayli o'tdi. - One-click obunadan chiqish — faqat POST va tasodifiy token.
- Hard bounce va shikoyat — darhol bostirish ro'yxatiga.
Keyingi dars: SMS provayderlar: Eskiz va PlayMobile — O'zbekistonda SMS yuborish: token, segmentlar narxi va bitta ʻ belgisi xabarni qanday qimmatlashtirishi.
Manbalar
- RFC 7208 — SPF: https://www.rfc-editor.org/rfc/rfc7208
- RFC 6376 — DKIM: https://www.rfc-editor.org/rfc/rfc6376
- RFC 7489 — DMARC: https://www.rfc-editor.org/rfc/rfc7489
- RFC 8058 — one-click
List-Unsubscribe-Post: https://www.rfc-editor.org/rfc/rfc8058 - RFC 5737 — hujjatlar uchun IP diapazonlari: https://www.rfc-editor.org/rfc/rfc5737
- Google — Email sender guidelines (5 000/kun, 0.10 % / 0.30 %, 2024-02-01 dan): https://support.google.com/a/answer/81126 — 2026-10-28 da tekshirildi
- Yahoo Sender Hub — best practices (SPF + DKIM, DMARC
p=none, one-click, 0.3 %): https://senders.yahooinc.com/best-practices/ — 2026-10-28 da tekshirildi - mailauth: https://github.com/postalsys/mailauth
- Kanon tajribasi (IlmHamroh, 2026-10-27): nodemailer 10.1.7, mailauth 8.0.1, DNS — soxta resolver, Node 24.21.0. Haqiqiy DNS, Gmail/Outlook, bounce/complaint webhook'lari — sinalmagan. One-click server, xom sarlavhalar va mashq yechimlari — biz ishga tushirdik (2026-10-28).
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!