Nodemailer — SMTP, Gmail, email yuborish

~20 daq · Express · Email va Xabarlar

Muammodan boshlaylik

Foydalanuvchi ro'yxatdan o'tdi. Endi unga "Xush kelibsiz!" emaili yuborilishi kerak. Yoki parolni unutdi — tasdiqlash kodi kerak. Buyurtma qildi — chek emaili kerak.

Bularning barchasida server o'zi email yuborishi lozim. Lekin email qanday ishlaydi? Server qayerdan yuboradi?


SMTP nima?

SMTP (Simple Mail Transfer Protocol) — emaillarni yuborish uchun protokol. Xuddi pochta idorasi kabi: siz konvert topshirasiz, ular manzilga yetkazadi.

Sizning server          Gmail SMTP           Qabul qiluvchi
    |                      |                      |
    |--- email (SMTP) ---->|                      |
    |                      |--- yetkazish ------->|
    |<-- OK ---------------|                      |

Nodemailer — Node.js da email yuborish uchun kutubxona. SMTP server bilan gaplashadi.


O'rnatish

npm install nodemailer

Transporter nima?

Tasavvur qiling: kuryer xizmati. Siz paketni berasiz, kuryer yetkazadi. Transporter — o'sha kuryer. Bir marta sozlanadi, keyin qayta-qayta ishlatiladi.

import nodemailer from 'nodemailer';

const transporter = nodemailer.createTransport({
  host: 'smtp.gmail.com', // ← SMTP server manzili
  port: 587,              // ← 587 (TLS) yoki 465 (SSL)
  secure: false,          // ← 587 da false, 465 da true
  auth: {
    user: process.env.EMAIL_USER, // ← gmail manzili
    pass: process.env.EMAIL_PASS, // ← app password (parol emas!)
  },
});

⚠️ pass — Gmail parolingiz emas. Google "App Password" yaratishni talab qiladi. Quyida tushuntiriladi.


Gmail App Password olish

Google oddiy parolni SMTP uchun qabul qilmaydi — xavfsizlik sababli. "App Password" — maxsus yaratilgan 16 belgili kod.

  1. Google Account → Security
  2. 2-Step Verification — yoqing (majburiy)
  3. App passwords → "Mail" → "Other" → nom bering
  4. 16 belgili kodni .env ga yozing
EMAIL_USER=siz@gmail.com
EMAIL_PASS=abcd efgh ijkl mnop

Email yuborish

const emailYuborish = async ({ kimga, mavzu, matn }) => {
  await transporter.sendMail({
    from: `"DevDocs" <${process.env.EMAIL_USER}>`, // ← kimdan
    to: kimga,                                      // ← kimga
    subject: mavzu,                                 // ← mavzu
    text: matn,                                     // ← oddiy matn
  });
};

// Ishlatish
await emailYuborish({
  kimga: 'ali@example.com',
  mavzu: 'Xush kelibsiz!',
  matn: 'DevDocs ga ro\'yxatdan o\'tdingiz.',
});

HTML email

await transporter.sendMail({
  from: `"DevDocs" <${process.env.EMAIL_USER}>`,
  to: 'ali@example.com',
  subject: 'Parolni tiklash',
  text: 'Parolni tiklash uchun: http://...', // ← HTML ko'rsatmasa fallback
  html: `
    <h2>Parolni tiklash</h2>
    <p>Quyidagi tugmani bosing:</p>
    <a href="http://localhost:3000/reset?token=abc123"
       style="background:#3b82f6;color:white;padding:12px 24px;text-decoration:none;border-radius:6px;">
      Parolni tiklash
    </a>
    <p>Link 1 soat davomida amal qiladi.</p>
  `,
});

💡 text ni ham yozing — ba'zi email mijozlar HTML ko'rsatmaydi. Ikkalasi birga bo'lsa — HTML ko'rsatsa HTML, ko'rsatmasa text.


Route bilan birlashtirish

// routes/auth.js
import express from 'express';
import crypto from 'crypto';
import nodemailer from 'nodemailer';

const router = express.Router();

const transporter = nodemailer.createTransport({
  host: 'smtp.gmail.com',
  port: 587,
  secure: false,
  auth: {
    user: process.env.EMAIL_USER,
    pass: process.env.EMAIL_PASS,
  },
});

// Parolni tiklash so'rovi
router.post('/forgot-password', async (req, res) => {
  const { email } = req.body;

  const foydalanuvchi = await db.users.findOne({ where: { email } });
  if (!foydalanuvchi) {
    // ← foydalanuvchi bormi yo'qmi aytmang — xavfsizlik
    return res.json({ xabar: 'Email yuborildi' });
  }

  // Tasdiqlash tokeni
  const token = crypto.randomBytes(32).toString('hex');
  const muddati = new Date(Date.now() + 60 * 60 * 1000); // 1 soat

  await db.resetTokens.create({ userId: foydalanuvchi.id, token, muddati });

  await transporter.sendMail({
    from: `"DevDocs" <${process.env.EMAIL_USER}>`,
    to: email,
    subject: 'Parolni tiklash',
    html: `
      <p>Parolni tiklash uchun bosing:</p>
      <a href="${process.env.CLIENT_URL}/reset?token=${token}">Parolni tiklash</a>
      <p>Link 1 soat amal qiladi.</p>
    `,
  });

  res.json({ xabar: 'Email yuborildi' });
});

Ulanishni tekshirish

Development da email yuborish o'rniga ulanishni tekshirish:

transporter.verify((error) => {
  if (error) {
    console.log('SMTP xatosi:', error.message);
  } else {
    console.log('SMTP tayyor');
  }
});

Ethereal — test uchun

Development da real email yuborishning hojati yo'q. Ethereal — soxta SMTP: email "yuboriladi", lekin aslida brauzerda ko'rib chiqasiz.

// Test transporter yaratish
const testTransporter = await nodemailer.createTestAccount();

const transporter = nodemailer.createTransport({
  host: 'smtp.ethereal.email',
  port: 587,
  auth: {
    user: testTransporter.user,
    pass: testTransporter.pass,
  },
});

const info = await transporter.sendMail({
  from: 'test@example.com',
  to: 'ali@example.com',
  subject: 'Test',
  text: 'Bu test email',
});

// Brauzerde ko'rish uchun URL
console.log('Preview:', nodemailer.getTestMessageUrl(info));
// → https://ethereal.email/message/...

💡 Ethereal — real emailga o'tishdan oldin shablonni tekshirishning eng qulay usuli. Real manzilga hech narsa ketmaydi.


Tez-tez uchraydigan xatolar

1. "Invalid login" xatosi

Error: Invalid login: 535-5.7.8 Username and Password not accepted

Sababi: oddiy Gmail parol ishlamaydi. App Password kerak (yuqorida tushuntirilgan).

2. "Less secure app access" xatosi

Google bu funksiyani 2022 yilda o'chirib tashladi. Yechim — faqat App Password.

3. Port xatosi

// ❌ — port va secure mos kelmayapti
{ port: 465, secure: false }
{ port: 587, secure: true }

// ✅
{ port: 465, secure: true }  // SSL
{ port: 587, secure: false } // TLS (STARTTLS)

4. Email spamga tushishi

  • from da to'g'ri manzil ko'rsating
  • text fallback qo'shing
  • Bir vaqtda juda ko'p email yubormang

Xulosa

  • Nodemailer — Node.js da email yuborish kutubxonasi; SMTP orqali ishlaydi
  • Gmail uchun App Password kerak — oddiy parol ishlamaydi
  • text va html ikkalasini yozing — email mijozlar farq qiladi
  • Development da Ethereal — real email yuborilmaydi, brauzerde ko'rasiz
  • transporter.verify() — ulanishni tekshirish

Keyingi dars: 47-dars: Email template — HTML email, Handlebars