5.19-bob: Email — Nodemailer
5-QISM — Node.js Backend · 19-mavzu
1. Kirish va motivatsiya
5.18-bobda SMS yuborishni o'rgandik. Endi ikkinchi muhim aloqa kanalini — email yuborishni — o'rganamiz. Email — backend'ning eng ko'p uchraydigan vazifalaridan biri: ro'yxatdan o'tishni tasdiqlash xati, parolni tiklash havolasi, buyurtma cheki, haftalik hisobot, bildirishnoma. SMS qisqa va pulli; email — uzun, bepul (deyarli), HTML bilan chiroyli, fayl biriktirsa bo'ladi.
Node.js'da email yuborishning standart vositasi — Nodemailer. Bu — eng mashhur, ishonchli, nol bog'liqlikli (zero-dependency) email kutubxonasi (nodemailer.com). U SMTP (Simple Mail Transfer Protocol — elektron pochta yuborish protokoli — 0.4) orqali email serverga ulanadi va xat yuboradi. Gmail, Outlook, yoki maxsus email xizmati (SendGrid, Mailtrap) — hammasi SMTP qo'llaydi.
Email yuborish oddiy ko'rinadi, lekin ko'p nozik joyi bor: yetkazib berish (deliverability — spam'ga tushmaslik), HTML shablon, fayl biriktirish, xavfsizlik (kalitlarni himoyalash), va og'ir email'larni fonda (navbat — 5.22) yuborish. Bu bobda hammasini quramiz.
O'xshatish: Nodemailer — pochta kuryeri. Siz xatni yozasiz (matn/HTML), konvertga manzil yozasiz (kimga/kimdan/mavzu), kuryerga berasiz (transporter). Kuryer pochta bo'limiga (SMTP server) eltadi, u manzilga yetkazadi. Konvertga rasm/hujjat (attachment) ham qo'shsa bo'ladi. Kuryer ishonchli bo'lishi (SMTP sozlamasi to'g'ri), aks holda xat yo'qoladi yoki "spam" qutiga tushadi.
Nega muhim?
- Deyarli har ilova — email tasdiqlash, parol tiklash, bildirishnoma.
- Ikkinchi kanal — SMS 5.18-bob qisqa/pulli; email uzun/HTML/bepul.
- Xavfsizlik (14) — parol tiklash havolasi, tasdiqlash — email orqali.
- Amaliy — SMTP, HTML shablon, attachment — real ko'nikma.
2. Nazariya — chuqur tushuntirish
2.1. Email qanday yuboriladi (SMTP)
Email SMTP 0.4-bob protokoli orqali yuboriladi. Siz to'g'ridan foydalanuvchining pochtasiga ulanmaysiz — email serverga (SMTP) topshirasiz, u yetkazadi:
Sizning botingiz SMTP server (Gmail/SendGrid) qabul qiluvchi pochta serveri foydalanuvchi
SMTP — "xat yuborish" protokoli (0.4: HTTP "veb" uchun, SMTP "email" uchun)
IMAP/POP3 — "xat o'qish" (bu bobda kerak emas — biz faqat yuboramiz)Muhim: siz faqat yuborasiz (SMTP). O'qish (kelgan xatlar) — boshqa protokol (IMAP/POP3) — bu bobda kerak emas. Backend odatda faqat yuboradi (tasdiqlash, bildirishnoma).
2.2. Nodemailer — uch qadam
Nodemailer bilan email yuborish — uch qadam (nodemailer.com):
1. Transporter yaratish — SMTP ulanish sozlamasi (kim orqali yuboramiz)
2. Xabar tuzish — kimdan, kimga, mavzu, matn/HTML
3. Yuborish — transporter.sendMail(xabar)import nodemailer from "nodemailer";
const transporter = nodemailer.createTransport({ /* SMTP */ }); // 1
const xabar = { from, to, subject, html }; // 2
await transporter.sendMail(xabar); // 32.3. Transporter — SMTP sozlamasi
Transporter — email serverga ulanish (host, port, login). Bir marta yaratiladi, qayta ishlatiladi (nodemailer):
const transporter = nodemailer.createTransport({
host: "smtp.gmail.com", // SMTP server manzili
port: 587, // port (587 — TLS; 465 — SSL)
secure: false, // 465 true; 587 false (STARTTLS)
auth: {
user: process.env.SMTP_USER, // login (email) — .env (14, 5.8)
pass: process.env.SMTP_PASS, // parol/app password — .env
},
});Transporter'ni BIR MARTA yarating (ilova boshida), har email uchun emas (nodemailer): yangi transporter — resurs isrofi. Markazlashtirilgan modul (5.8 config kabi). Kalitlar .env'da (14).
2.4. Portlar va shifrlash (587 vs 465)
port 587 + secure:false — STARTTLS (ulanib, keyin shifrlashga o'tadi) — tavsiya
port 465 + secure:true — SSL (boshidan shifrlangan)
port 25 — shifrlanmagan (ishlatmang — bloklangan, xavfsiz emas — 14)Ko'p provayder 587 (STARTTLS) tavsiya qiladi. Ikkalasi ham shifrlangan; loyiha/provayderga qarab.
2.5. Xabar tuzilishi (message)
const xabar = {
from: '"Mana Do'kon" <info@mana.uz>', // kimdan (ism + email)
to: "user@example.com", // kimga (vergul bilan ko'p)
subject: "Xush kelibsiz!", // mavzu
text: "Oddiy matn versiyasi", // matn (HTML'siz mijozlar uchun)
html: "<h1>Salom!</h1>", // HTML versiyasi (2.6)
attachments: [], // fayllar (2.7)
};
textvahtmlikkalasi ham bering: ko'p email mijozi HTML ko'rsatadi, lekin ba'zilari (yoki spam filtri)textversiyasini istaydi. Ikkalasi bo'lsa — yetkazib berish yaxshilanadi 2.10-bob.
2.6. HTML email (chiroyli xat)
Email HTML bilan bezatiladi, lekin oddiy HTML/CSS emas — email mijozlari (Gmail, Outlook) cheklangan:
Email HTML — eski, cheklangan:
- Tashqi CSS yo'q (inline style ishlatiladi: style="...")
- Flexbox/Grid (1.3, 1.4) ko'pincha ishlamaydi <table> bilan layout (eski usul)
- JavaScript yo'q (xavfsizlik)
- Har mijoz har xil ko'rsatadi (test kerak)Yechim: email shablon kutubxonasi (
mjml,react-email) yoki tayyor shablon. Murakkab dizayn — qiyin; oddiy (logo, matn, tugma) — qo'lda inline style bilan. Test uchun Mailtrap 2.11-bob.
2.7. Attachment (fayl biriktirish)
attachments: [
{ filename: "chek.pdf", path: "./files/chek.pdf" }, // diskdan (5.3)
{ filename: "rasm.png", content: buffer }, // Buffer'dan (0.1)
{ filename: "hisobot.csv", content: "a,b,c", contentType: "text/csv" }, // matndan
{ filename: "logo.png", path: "./logo.png", cid: "logo" }, // HTML ichida: <img src="cid:logo">
]
cid(Content-ID) — rasmni HTML ichiga joylash (xat ichidagi logo).<img src="cid:logo">— biriktirilgan rasmga ishora. Tashqi URL'dan rasm ko'p mijozda bloklanadi; cid — ishonchli.
2.8. transporter.verify() — sozlamani tekshirish
Email yuborishdan oldin SMTP ulanishi to'g'riligini tekshirish (nodemailer):
// Ilova boshida — sozlama xatosini erta aniqlash
try {
await transporter.verify();
console.log("SMTP tayyor");
} catch (err) {
console.error("SMTP xato:", err); // kalit/host noto'g'ri — darrov bilasiz
}Foyda:
verify()SMTP ulanish va loginni yuborishdan oldin tekshiradi — noto'g'ri kalitni darrov aniqlaysiz (har email'da xato chiqishini kutmasdan).
2.9. Og'ir email'lar — fonda yuborish (navbat — 5.22)
Email yuborish sekin bo'lishi mumkin (SMTP javobini kutish — bir necha sekund). Foydalanuvchini kutdirmang — email'ni fonda (navbat — 5.22: BullMQ) yuboring:
So'rovda email kutish:
POST /signup ... email yubor (3 sek kutadi!) javob (sekin UX)
Navbatga qo'yib, darrov javob:
POST /signup ... navbatga "email yubor" qo'sh javob (tez)
fonda: worker navbatdan oladi email yuboradi (foydalanuvchi kutmaydi)Bu — 5.22 (BullMQ) mavzusi. Hozir oddiy (to'g'ridan) yuborishni o'rganamiz; production'da og'ir/ko'p email — navbat orqali 5.22-bob.
Xato va qayta urinish (retry): SMTP vaqtincha javob bermasligi mumkin (tarmoq, server band).
sendMailxato (reject) qaytarsa —try/catchbilan ushlang 5.10-bob, logga yozing 5.12-bob. Bitta email muhim bo'lsa — qayta urinish kerak: navbatda (5.22: BullMQ) bu avtomatik (attempts: 3, eksponensial kechikish). Qo'lda esa — bir necha marta, ortib boruvchi pauza bilan. Lekin cheksiz urinmang (spam/bloklash); 3–5 urinishdan keyin "o'lik xat" (dead-letter) sifatida belgilang.
2.10. Yetkazib berish (deliverability — spam'ga tushmaslik)
Email'ning eng qiyin qismi — spam papkaga tushmaslik (mailtrap/nodemailer):
SPF, DKIM, DMARC — domen autentifikatsiyasi (email haqiqiyligini isbotlaydi)
Ishonchli "from" domeni (o'z domening: info@mana.uz, gmail emas)
text + html ikkalasi 2.5-bob
Spam so'zlardan saqlanish ("BEPUL!!!", ko'p katta harf)
Production'da dedikatsiyalangan xizmat (SendGrid/Resend — 2.12)DKIM — Nodemailer'ning
dkimopsiyasi bilan avtomatik imzolanadi (nodemailer). Bu — yetkazib berish uchun muhim. Lekin SPF/DMARC — DNS sozlamasi (domen darajasida — 0.4).
2.11. Test qilish (Mailtrap, Ethereal)
Dev'da haqiqiy email yubormang (foydalanuvchiga keraksiz xat). Test SMTP:
Mailtrap.io — test inbox (email yuboriladi, lekin Mailtrap'da ushlanadi — chiqmaydi)
Ethereal — Nodemailer'ning test akkaunti (nodemailer.createTestAccount)Mailtrap — dev'da ideal: email "yuboriladi", lekin haqiqiy odamga bormaydi — Mailtrap panelida ko'rasiz (HTML, spam ball, hammasi). Foydalanuvchiga tasodifan xat ketishidan saqlaydi.
2.12. Production: dedikatsiyalangan xizmat (Nodemailer + API)
Nodemailer to'g'ridan SMTP (Gmail) — kichik loyiha uchun
Production — dedikatsiyalangan: SendGrid, Resend, Amazon SES, Mailgun
yetkazib berish, retry, bounce, analitika — ular hal qiladi (2.10)Nodemailer bu xizmatlarning SMTP'siga ham ulanadi (transporter sozlamasini almashtirasiz). Yoki ularning API'sini ishlatasiz. Kichik loyiha — Gmail SMTP; jiddiy — dedikatsiyalangan (mailtrap/pkgpulse 2026).
2.13. Email use-case'lar (qo'llanish)
Tasdiqlash xati — ro'yxatdan o'tgach, email tasdiqlash havolasi/kodi
Parol tiklash — "parolni unutdingiz" tiklash havolasi (token bilan — 14)
Xush kelibsiz — ro'yxatdan o'tgach
Buyurtma cheki — to'lovdan keyin (PDF attachment — 2.7)
Bildirishnoma — hodisa (yangi xabar, eslatma)
Hisobot — davriy (haftalik — cron — 5.22)Transactional vs marketing email: ikki tur farqlanadi. Transactional (transaksion) — bitta foydalanuvchi harakatiga javoban (tasdiqlash, parol tiklash, chek) — yuqori ustuvor, darrov yetishi shart; bu bobdagi misollar shu. Marketing (ommaviy axborot/reklama) — ko'p qabul qiluvchiga bir vaqtda (yangiliklar, aksiya) — bu yerda "obunadan chiqish" (unsubscribe) havolasi majburiy (qonun talabi — CAN-SPAM/GDPR), va alohida obro'-domen tavsiya etiladi (marketing spam'i transaksion xatlaringizning yetkazib berilishiga zarar bermasligi uchun). Backend odatda transactional bilan ishlaydi; marketing — alohida xizmat (Mailchimp va h.k.).
2.14. Xavfsizlik amaliyotlari (14)
SMTP kalitlari .env'da (kodda emas — 14, 5.8)
Gmail uchun "App Password" (asosiy parol emas — 2.3, 14)
Parol tiklash: tasodifiy token (crypto — 5.3), qisqa muddat, bir martalik (5.18 ruhida)
Email manzilini validatsiya 5.9-bob; foydalanuvchi kiritgan HTML'ni email'ga solmang (XSS — 14)
Rate limiting (email spam — 5.20)
Foydalanuvchi ma'lumotini email'da ehtiyotkor (PII — 14)3. Sintaksis — tez ma'lumotnoma
import nodemailer from "nodemailer";
// Transporter (bir marta — 2.3)
const transporter = nodemailer.createTransport({
host, port: 587, secure: false, auth: { user, pass },
});
// Tekshirish (2.8)
await transporter.verify();
// Yuborish (2.2)
await transporter.sendMail({
from: '"Nom" <a@b.uz>', to, subject, text, html, // (2.5, 2.6)
attachments: [{ filename, path }], // (2.7)
});4. Batafsil kod namunalari
Misol 1 — Asosiy email yuborish (2.2, 2.3)
import nodemailer from "nodemailer";
import { config } from "../config/index.js"; // (5.8)
// Transporter (bir marta — 2.3)
const transporter = nodemailer.createTransport({
host: config.smtp.host, // smtp.gmail.com
port: 587, // STARTTLS (2.4)
secure: false,
auth: { user: config.smtp.user, pass: config.smtp.pass }, // .env (14)
});
// Yuborish funksiyasi
export async function emailYubor({ to, subject, text, html }) {
const info = await transporter.sendMail({
from: `"Mana Do'kon" <${config.smtp.user}>`, // kimdan (2.5)
to, subject, text, html,
});
return info.messageId; // yuborilgan xat ID'si
}
// Ishlatish
await emailYubor({
to: "user@example.com",
subject: "Xush kelibsiz!",
text: "Ro'yxatdan o'tganingiz uchun rahmat",
html: "<h1>Xush kelibsiz!</h1><p>Ro'yxatdan o'tdingiz.</p>",
});Misol 2 — Transporter verify (sozlama tekshiruvi — 2.8)
// Ilova boshida — SMTP to'g'riligini erta aniqlash (2.8)
export async function smtpTekshir() {
try {
await transporter.verify();
console.log(" SMTP ulanish tayyor");
} catch (err) {
console.error(" SMTP sozlama xato:", err.message); // kalit/host noto'g'ri
// production'da: ogohlantirish (5.12)
}
}
// server.js da: await smtpTekshir();Misol 3 — HTML email shablon (inline style — 2.6)
// Email HTML — inline style (tashqi CSS ishlamaydi — 2.6)
function xushKelibsizHtml(ism) {
return `
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
<div style="background: #4f46e5; padding: 24px; text-align: center;">
<h1 style="color: #fff; margin: 0;">Mana Do'kon</h1>
</div>
<div style="padding: 24px; color: #333;">
<p>Assalomu alaykum, <strong>${ism}</strong>!</p>
<p>Ro'yxatdan o'tganingiz uchun rahmat.</p>
<a href="https://mana.uz/start"
style="display:inline-block; background:#4f46e5; color:#fff;
padding:12px 24px; border-radius:6px; text-decoration:none;">
Boshlash
</a>
</div>
<div style="padding:16px; text-align:center; color:#999; font-size:12px;">
© 2026 Mana Do'kon
</div>
</div>`;
}
await emailYubor({
to: user.email,
subject: "Xush kelibsiz!",
text: `Salom ${user.ism}! Ro'yxatdan o'tdingiz.`, // matn versiya (2.5)
html: xushKelibsizHtml(user.ism),
});Misol 4 — Email tasdiqlash (verification — 2.13, 14)
import crypto from "node:crypto"; // (5.3)
export const emailTasdiqYubor = async (user) => {
// Tasodifiy token (5.3, 14)
const token = crypto.randomBytes(32).toString("hex");
// DB'da saqlash (muddat bilan — 5.18 ruhida)
await EmailToken.create({
userId: user.id, token, expiresAt: new Date(Date.now() + 24 * 3600 * 1000), // 24 soat
});
// Tasdiqlash havolasi
const url = `${config.clientUrl}/verify-email?token=${token}`;
await emailYubor({
to: user.email,
subject: "Email manzilingizni tasdiqlang",
text: `Tasdiqlash: ${url}`,
html: `<p>Tasdiqlash uchun bosing:</p>
<a href="${url}">Email'ni tasdiqlash</a>
<p>Havola 24 soat amal qiladi.</p>`,
});
};
// Tasdiqlash endpoint'i
export const emailTasdiqla = async (req, res, next) => {
try {
const { token } = req.query;
const yozuv = await EmailToken.findOne({ token, expiresAt: { $gt: new Date() } });
if (!yozuv) return res.status(400).json({ error: "Havola yaroqsiz/muddati tugagan" });
await User.findByIdAndUpdate(yozuv.userId, { emailTasdiqlangan: true });
await yozuv.deleteOne(); // bir martalik (5.18)
res.json({ message: "Email tasdiqlandi" });
} catch (err) { next(err); }
};Misol 5 — Parol tiklash (password reset — 2.13, 14)
import crypto from "node:crypto";
import bcrypt from "bcrypt";
// 1. Tiklash so'rovi (havola yuborish)
export const parolTiklashSorov = async (req, res, next) => {
try {
const { email } = req.body; // (5.9)
const user = await User.findOne({ email });
// Foydalanuvchi bor/yo'qligini OSHKOR QILMA (14, 5.15)
if (user) {
const token = crypto.randomBytes(32).toString("hex"); // (5.3)
user.resetToken = await bcrypt.hash(token, 10); // hash (DB sizsa — 14)
user.resetExpires = new Date(Date.now() + 3600000); // 1 soat
await user.save();
const url = `${config.clientUrl}/reset-password?token=${token}&id=${user.id}`;
await emailYubor({
to: email, subject: "Parolni tiklash",
html: `<p>Parolni tiklash uchun:</p><a href="${url}">Tiklash</a>
<p>1 soat amal qiladi. So'ramagan bo'lsangiz, e'tiborsiz qoldiring.</p>`,
});
}
// Doim bir xil javob (oshkor qilmaslik — 14)
res.json({ message: "Agar email mavjud bo'lsa, havola yuborildi" });
} catch (err) { next(err); }
};
// 2. Yangi parol o'rnatish
export const parolTiklash = async (req, res, next) => {
try {
const { id, token, yangiParol } = req.body;
const user = await User.findById(id).select("+resetToken +resetExpires");
if (!user || !user.resetExpires || user.resetExpires < new Date() ||
!(await bcrypt.compare(token, user.resetToken))) { // tekshirish (14)
return res.status(400).json({ error: "Havola yaroqsiz/muddati tugagan" });
}
user.parol = await bcrypt.hash(yangiParol, 12); // yangi parol (5.15)
user.resetToken = undefined; user.resetExpires = undefined; // bir martalik
await user.save();
res.json({ message: "Parol tiklandi" });
} catch (err) { next(err); }
};Misol 6 — Attachment bilan (buyurtma cheki — 2.7)
// PDF chek biriktirish (2.7)
await emailYubor({
to: user.email,
subject: `Buyurtma #${buyurtma.id} cheki`,
html: `<p>Buyurtmangiz uchun rahmat! Chek ilova qilingan.</p>`,
attachments: [
{ filename: `chek-${buyurtma.id}.pdf`, path: `./cheklar/${buyurtma.id}.pdf` }, // diskdan
{ filename: "logo.png", path: "./assets/logo.png", cid: "logo" }, // HTML ichida
],
});
// HTML'da: <img src="cid:logo"> — biriktirilgan logo (2.7)Misol 7 — Markazlashtirilgan email xizmati (2.3, 9)
// services/email.js — barcha email mantig'i bir joyda (9: SOLID)
import nodemailer from "nodemailer";
import { config } from "../config/index.js";
class EmailService {
constructor() {
this.transporter = nodemailer.createTransport({ // bir marta (2.3)
host: config.smtp.host, port: 587, secure: false,
auth: { user: config.smtp.user, pass: config.smtp.pass },
pool: true, // connection pooling (ko'p email — 2.3)
});
}
async send({ to, subject, text, html, attachments }) {
return this.transporter.sendMail({
from: `"${config.appName}" <${config.smtp.user}>`,
to, subject, text, html, attachments,
});
}
// Maxsus metodlar
xushKelibsiz(user) {
return this.send({ to: user.email, subject: "Xush kelibsiz!", html: xushKelibsizHtml(user.ism) });
}
parolTiklash(email, url) {
return this.send({ to: email, subject: "Parolni tiklash", html: `<a href="${url}">Tiklash</a>` });
}
}
export const emailService = new EmailService();Misol 8 — Dev'da Mailtrap (test — 2.11)
// Dev'da test SMTP (haqiqiy email yuborilmaydi — 2.11)
const transporter = nodemailer.createTransport(
config.isProd
? { host: config.smtp.host, port: 587, secure: false, auth: {...} } // production
: { // dev: Mailtrap
host: "sandbox.smtp.mailtrap.io", port: 2525,
auth: { user: config.mailtrap.user, pass: config.mailtrap.pass },
}
);
// Dev'da email Mailtrap panelida ko'rinadi (foydalanuvchiga bormaydi — 2.11)5. To'g'ri va noto'g'ri holatlar
1) Har email uchun yangi transporter
// resurs isrofi (2.3)
async function send() { const t = nodemailer.createTransport(...); await t.sendMail(...); }
// bir marta (modul darajasida)
const transporter = nodemailer.createTransport(...);2) SMTP kalitlarini kodda saqlash
// kodda (14, 5.8)
auth: { user: "a@gmail.com", pass: "parol123" }
// .env
auth: { user: config.smtp.user, pass: config.smtp.pass }3) Parol tiklashda foydalanuvchi bor/yo'qligini oshkor qilish
// "bunday email yo'q" hacker emaillarni aniqlaydi (14, Misol 5)
if (!user) return res.json({ error: "Email topilmadi" });
// doim bir xil javob
res.json({ message: "Agar email mavjud bo'lsa, havola yuborildi" });4) Faqat HTML (text'siz)
// text yo'q spam'ga moyil, ba'zi mijoz ko'rmaydi (2.5, 2.10)
{ html: "<h1>...</h1>" }
// ikkalasi
{ text: "...", html: "<h1>...</h1>" }5) So'rovda email kutish (sekin UX)
// foydalanuvchi 3 sekund kutadi (2.9)
await emailYubor(...); res.json({ ok: true });
// navbatga qo'y, darrov javob (5.22)
emailQueue.add("welcome", { userId }); res.json({ ok: true });6. Keng tarqalgan xatolar va yechimlari
Xato 1 — EAUTH / Invalid login
Sababi: SMTP login/parol noto'g'ri; Gmail'da oddiy parol (App Password kerak — 2.14). Yechimi: App Password yarating (Gmail 2FA bilan); kalitlar .env'da; verify() bilan tekshiring 2.8-bob.
Xato 2 — Email spam papkaga tushadi
Sababi: SPF/DKIM/DMARC yo'q; ishonchsiz "from"; spam so'zlar 2.10-bob. Yechimi: domen autentifikatsiyasi; o'z domeni; text+html; dedikatsiyalangan xizmat 2.12-bob.
Xato 3 — ECONNREFUSED / ETIMEDOUT
Sababi: host/port noto'g'ri, yoki firewall SMTP portni bloklagan 0.4-bob. Yechimi: host/port tekshiring (587/465 — 2.4); server SMTP'ga ruxsatmi.
Xato 4 — HTML email buzilib ko'rinadi
Sababi: tashqi CSS/Flexbox ishlatilgan (email cheklangan — 2.6). Yechimi: inline style; <table> layout; shablon kutubxonasi (mjml).
Xato 5 — Rasm ko'rinmaydi (HTML'da)
Sababi: tashqi URL bloklangan (mijoz). Yechimi: cid bilan biriktirish (Misol 6, 2.7).
Xato 6 — Email yuborish so'rovni sekinlashtiradi
Sababi: to'g'ridan, kutib yuborish 2.9-bob. Yechimi: navbat (BullMQ — 5.22).
7. Integratsiya — bu mavzu stack'ning qayerida uchraydi
- HTTP/SMTP 0.4-bob: email protokoli.
- crypto 5.3-bob: tasdiqlash/tiklash tokeni.
- Auth 5.15-bob: email tasdiqlash, parol tiklash.
- OTP 5.18-bob: email OTP (SMS muqobili).
- Env 5.8-bob: SMTP kalitlari.
- Validatsiya 5.9-bob: email format.
- Navbat 5.22-bob: og'ir email fonda; davriy hisobot (cron).
- Rate limiting 5.20-bob: email spam himoyasi.
- DB (6): email token saqlash.
- NestJS 8.18-bob: @nestjs-modules/mailer — shu g'oya.
8. Eng yaxshi amaliyotlar (best practices)
- Transporter bir marta (pool bilan ko'p email — 2.3).
- SMTP kalitlari .env'da (Gmail App Password — 2.14, 14).
verify()ilova boshida (sozlama xatosini erta — 2.8).- text + html ikkalasi (yetkazib berish — 2.5, 2.10).
- HTML — inline style (
<table>layout — 2.6). - Parol tiklash: token hash, qisqa muddat, bir martalik; oshkor qilma (14, Misol 5).
- Og'ir/ko'p email — navbatda (BullMQ — 5.22, 2.9).
- Dev'da Mailtrap (haqiqiy email yubormang — 2.11).
- Production'da dedikatsiyalangan xizmat (SendGrid/Resend — 2.12).
- Yetkazib berish (SPF/DKIM/DMARC, o'z domeni — 2.10); email format validatsiya 5.9-bob.
9. Amaliy loyiha: "Email Xizmati (tasdiqlash + parol tiklash)"
Email yuborishni professional darajada mustahkamlash.
Maqsad
Nodemailer bilan markazlashtirilgan email xizmatini qurish: xush kelibsiz, email tasdiqlash, parol tiklash, HTML shablon va attachment.
Talablar (requirements)
- Markazlashtirilgan EmailService: transporter bir marta (pool); maxsus metodlar (Misol 7, 2.3).
- verify(): ilova boshida SMTP tekshiring (Misol 2, 2.8).
- HTML shablon: inline style, logo, tugma; text versiya (Misol 3, 2.5, 2.6).
- Email tasdiqlash: token (crypto) + havola + tasdiqlash endpoint; muddat (Misol 4, 2.13).
- Parol tiklash: token hash, qisqa muddat, bir martalik; foydalanuvchi oshkor qilmaslik (Misol 5, 14).
- Attachment: PDF chek + cid logo (Misol 6, 2.7).
- Xavfsizlik: kalitlar .env; email validatsiya; rate limiting (2.14, 5.9, 5.20).
- (Bonus) Dev'da Mailtrap (Misol 8, 2.11).
- (Bonus) Navbat: email'ni fonda yuborish (5.22, 2.9).
Maslahatlar (hint)
- Transporter modul darajasida (bir marta — 1-xato).
- Gmail: App Password (2FA bilan — 2.14, Xato 1).
- HTML: inline style,
<table>(2.6, 4-xato). - Token:
crypto.randomBytes(32).toString("hex")5.3-bob. - Parol tiklash: hash token, doim bir xil javob (14, 3-xato).
- cid:
attachments: [{ ..., cid: "logo" }]+<img src="cid:logo">2.7-bob.
"Tayyor" mezonlari (acceptance criteria)
- EmailService — transporter bir marta; metodlar.
- verify() SMTP'ni tekshiradi.
- HTML shablon chiroyli (text bilan).
- Email tasdiqlash (token, havola, muddat) ishlaydi.
- Parol tiklash xavfsiz (hash token, oshkor qilmaslik).
- Attachment (PDF + cid logo).
- Kalitlar .env; email validatsiya; rate limit.
- (Bonus) Mailtrap / navbat.
Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.
10. Xulosa va keyingi bobga ko'prik
Bu bobda ikkinchi muhim aloqa kanalini — email yuborish (Nodemailer) ni — o'rgandik:
- SMTP 0.4-bob orqali yuborish 2.1-bob; Nodemailer uch qadam (transporter xabar yuborish — 2.2).
- Transporter (SMTP sozlama, bir marta — 2.3); portlar (587/465 — 2.4); xabar (from/to/subject/text/html — 2.5).
- HTML email (inline style, cheklangan — 2.6); attachment (cid logo — 2.7); verify() 2.8-bob.
- Og'ir email — navbatda (5.22, 2.9); yetkazib berish (SPF/DKIM, spam — 2.10); Mailtrap test 2.11-bob.
- Use-case'lar (tasdiqlash, parol tiklash — 2.13); xavfsizlik (kalitlar .env, token hash, oshkor qilmaslik — 2.14, 14).
Keyingi bob — 5.20-bob: Xavfsizlik — Rate limiting, helmet, CORS. Auth (5.15-5.18) va email/SMS'ni bildik. Endi backend xavfsizligining muhim qatlamini — helmet (xavfsizlik header'lari), CORS (cross-origin nazorati), va rate limiting (so'rovlarni cheklash) — chuqur o'rganamiz. Bu uchtasi — har Express ilovaning majburiy himoyasi (OWASP).
Foydalanilgan rasmiy/ishonchli manbalar
- nodemailer.com — Nodemailer (transporter, SMTP, HTML, attachments, verify, dkim, pool)
- Mailtrap — Nodemailer tutorial 2026 (deliverability, test); nodejs.org — crypto (token)
- pkgpulse — best email libraries 2026 (production: SendGrid/Resend)
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!