WisarWisar
Dasturlash kitobi/5-QISM — Nodejs17 daqiqa

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:

text
  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):

text
  1. Transporter yaratish — SMTP ulanish sozlamasi (kim orqali yuboramiz)
  2. Xabar tuzish — kimdan, kimga, mavzu, matn/HTML
  3. Yuborish — transporter.sendMail(xabar)
js
import nodemailer from "nodemailer";

const transporter = nodemailer.createTransport({ /* SMTP */ });   // 1
const xabar = { from, to, subject, html };                        // 2
await transporter.sendMail(xabar);                                // 3

2.3. Transporter — SMTP sozlamasi

Transporter — email serverga ulanish (host, port, login). Bir marta yaratiladi, qayta ishlatiladi (nodemailer):

js
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)

text
  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)

js
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)
};

text va html ikkalasi ham bering: ko'p email mijozi HTML ko'rsatadi, lekin ba'zilari (yoki spam filtri) text versiyasini 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:

text
   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)

js
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):

js
// 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:

text
   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). sendMail xato (reject) qaytarsa — try/catch bilan 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):

text
   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 dkim opsiyasi 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:

text
  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)

text
  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)

text
  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)

text
   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

js
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)

js
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)

js
// 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)

js
// 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)

js
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)

js
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)

js
// 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)

js
// 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)

js
// 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

js
//  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

js
//  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

js
//  "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)

js
//  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)

js
//  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)

  1. Markazlashtirilgan EmailService: transporter bir marta (pool); maxsus metodlar (Misol 7, 2.3).
  2. verify(): ilova boshida SMTP tekshiring (Misol 2, 2.8).
  3. HTML shablon: inline style, logo, tugma; text versiya (Misol 3, 2.5, 2.6).
  4. Email tasdiqlash: token (crypto) + havola + tasdiqlash endpoint; muddat (Misol 4, 2.13).
  5. Parol tiklash: token hash, qisqa muddat, bir martalik; foydalanuvchi oshkor qilmaslik (Misol 5, 14).
  6. Attachment: PDF chek + cid logo (Misol 6, 2.7).
  7. Xavfsizlik: kalitlar .env; email validatsiya; rate limiting (2.14, 5.9, 5.20).
  8. (Bonus) Dev'da Mailtrap (Misol 8, 2.11).
  9. (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!
5.19-bob: Email — Nodemailer — Wisar