Untuk pemula — tinggal ikuti & klik Salin
Integrasi email & autentikasi Gmail (gratis)
Mau website kamu bisa kirim email verifikasi, OTP, atau reset password? Ada dua jalur gratis yang sama-sama berfungsi sempurna: Resend (paling mudah, deliverability bagus) atau Gmail SMTPpakai App Password. Pilih salah satu — setiap nilai & kode ada tombol Salin.
Resend
3.000 email/bulan gratis, setup 5 menit.
Gmail SMTP
Tanpa daftar layanan, cukup App Password.
Aman
Pakai App Password & env, bukan password asli.
Resend vs Gmail SMTP — pilih yang mana?
Keduanya gratis dan bisa dipakai dari website Next.js kamu. Bedanya cuma soal kemudahan dan batas pemakaian:
| Hal | Resend | Gmail SMTP |
|---|---|---|
| Biaya | Gratis 3.000/bulan | Gratis (kuota Gmail) |
| Batas harian | 100/hari (free) | ±500/hari |
| Setup | Daftar + 1 API key | Aktifkan App Password |
| Masuk inbox | Sangat baik | Baik untuk volume kecil |
| Cocok untuk | Produksi & skala | Proyek pribadi/uji coba |
lib/email.ts.Yang perlu disiapkan
Sebuah project Next.js (App Router) dan salah satu dari ini, sesuai jalur yang kamu pilih:
Jalur A — akun Resend
Daftar gratis di resend.com untuk dapat API key.
Jalur B — akun Gmail + 2FA
Verifikasi 2 langkah aktif agar bisa bikin App Password.
Jalur A — Resend (paling mudah)
Buka resend.com/signup, daftar gratis, lalu masuk ke menu API Keys → Create API Key. Salin kuncinya (diawali re_) dan simpan baik-baik.
Pasang paket Resend di project kamu:
# pakai pnpm
pnpm add resend
# atau npm
npm install resend@domainkamu.com.Sudah punya API key? Lewati Langkah 4 & 5 dan lompat ke Langkah 6 untuk menyimpan env.
Jalur B — Gmail SMTP gratis
Tidak perlu daftar layanan apa pun. Kamu hanya akan mengaktifkan Verifikasi 2 Langkah lalu membuat App Password 16 karakter khusus untuk aplikasi kamu. Server SMTP Gmail yang dipakai:
Buat App Password Gmail
App Password hanya muncul jika Verifikasi 2 Langkah sudah aktif. Ikuti urutan ini:
- 1Buka myaccount.google.com/security lalu aktifkan 2-Step Verification.
- 2Setelah aktif, buka myaccount.google.com/apppasswords.
- 3Beri nama, misal , lalu klik Create.
- 4Google menampilkan 16 huruf (contoh
abcd efgh ijkl mnop). Salin tanpa spasi jadiabcdefghijklmnop.
Lalu pasang paket pengirim email (nodemailer):
# pakai pnpm
pnpm add nodemailer
pnpm add -D @types/nodemailer
# atau npm
npm install nodemailer
npm install --save-dev @types/nodemailerSimpan environment variables
Buat file .env.local di root project. Pakai blok sesuai jalur yang kamu pilih — salah satu saja.
Jalur A — Resend:
# .env.local (Jalur A — Resend)
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxx
EMAIL_FROM="Nama Kamu <onboarding@resend.dev>"Jalur B — Gmail SMTP:
# .env.local (Jalur B — Gmail SMTP gratis)
GMAIL_USER=emailkamu@gmail.com
GMAIL_APP_PASSWORD=abcdefghijklmnop
EMAIL_FROM="Nama Kamu <emailkamu@gmail.com>".env.local ke Git. Pastikan ada di .gitignore. Saat deploy ke Vercel, tambahkan nilai yang sama di Project Settings → Environment Variables.Tulis kode pengirim email (lib/email.ts)
Buat satu file lib/email.ts berisi fungsi sendEmail(). Seluruh aplikasi cukup memanggil fungsi ini. Pilih isi sesuai jalurmu:
Jalur A — versi Resend:
// lib/email.ts — pengirim email pakai Resend
import { Resend } from 'resend'
const resend = new Resend(process.env.RESEND_API_KEY)
export async function sendEmail({
to,
subject,
html,
}: {
to: string
subject: string
html: string
}) {
const { data, error } = await resend.emails.send({
from: process.env.EMAIL_FROM!,
to,
subject,
html,
})
if (error) {
console.log('[v0] Resend error:', error)
throw new Error(error.message)
}
return data
}Jalur B — versi Gmail SMTP:
// lib/email.ts — pengirim email pakai Gmail SMTP (gratis)
import nodemailer from 'nodemailer'
// Transport SMTP Gmail. Pakai App Password, BUKAN password Gmail biasa.
const transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 465,
secure: true, // 465 = SSL
auth: {
user: process.env.GMAIL_USER,
pass: process.env.GMAIL_APP_PASSWORD, // 16 karakter App Password
},
})
export async function sendEmail({
to,
subject,
html,
}: {
to: string
subject: string
html: string
}) {
const info = await transporter.sendMail({
from: process.env.EMAIL_FROM,
to,
subject,
html,
})
console.log('[v0] Email terkirim:', info.messageId)
return info
}sendEmail() bentuknya sama persis di kedua jalur. Jadi kalau nanti mau pindah dari Gmail ke Resend, kamu cukup ganti isi file ini tanpa mengubah kode lain.Buat API route untuk kirim email
Sekarang buat endpoint app/api/send-email/route.ts yang memanggil sendEmail(). Contoh ini mengirim kode verifikasi 6 digit — pola yang sama dipakai untuk OTP, reset password, atau notifikasi.
// app/api/send-email/route.ts
import { NextResponse } from 'next/server'
import { sendEmail } from '@/lib/email'
export async function POST(req: Request) {
try {
const { to } = await req.json()
// contoh: kirim kode verifikasi 6 digit
const code = Math.floor(100000 + Math.random() * 900000).toString()
await sendEmail({
to,
subject: 'Kode verifikasi kamu',
html: `
<div style="font-family:sans-serif;max-width:480px;margin:auto">
<h2>Kode verifikasi</h2>
<p>Masukkan kode ini untuk melanjutkan:</p>
<p style="font-size:28px;font-weight:bold;letter-spacing:6px">${code}</p>
<p style="color:#888;font-size:13px">Berlaku 10 menit. Abaikan jika bukan kamu.</p>
</div>
`,
})
// TODO: simpan "code" ke database/redis untuk dicocokkan nanti
return NextResponse.json({ ok: true })
} catch (err) {
console.log('[v0] Gagal kirim email:', err)
return NextResponse.json({ ok: false, error: 'Gagal mengirim email' }, { status: 500 })
}
}code ke database atau Redis dengan masa berlaku, lalu cocokkan saat user memasukkannya. Jangan mengirim balik kode itu sebagai respons API.Uji coba & verifikasi
Jalankan dev server (pnpm dev), lalu tembak endpoint-nya dari terminal. Ganti alamat tujuan dengan email kamu:
# uji coba kirim email dari terminal
curl -X POST http://localhost:3000/api/send-email \
-H "Content-Type: application/json" \
-d '{"to":"tujuanmu@gmail.com"}'Khusus Gmail, kamu bisa cek koneksi SMTP-nya dulu tanpa mengirim apa pun (jalankan setelah memuat env, mis. lewat pnpm dev atau node --env-file=.env.local):
# verifikasi koneksi SMTP Gmail (opsional, debug cepat)
node -e "const n=require('nodemailer');n.createTransport({host:'smtp.gmail.com',port:465,secure:true,auth:{user:process.env.GMAIL_USER,pass:process.env.GMAIL_APP_PASSWORD}}).verify().then(()=>console.log('SMTP OK')).catch(e=>console.log('SMTP ERROR',e.message))"Selesai!
Website kamu sekarang bisa mengirim email verifikasi/OTP secara gratis. Kembali ke panduan deploy.
Atasi masalah umum
| Gejala | Solusi |
|---|---|
| Gmail: "Invalid login / 535" | Pakai App Password (16 huruf tanpa spasi), bukan password biasa. Pastikan 2FA aktif. |
| Gmail: "Username and Password not accepted" | GMAIL_USER harus email lengkap, dan App Password belum dicabut. |
| Email masuk folder Spam | Verifikasi domain (Resend) atau kirim volume kecil & isi yang wajar (Gmail). |
| Resend: 403 / unauthorized | RESEND_API_KEY salah/terhapus. Buat ulang di dashboard Resend. |
| env undefined saat runtime | Restart dev server setelah mengubah .env.local; di Vercel set env lalu redeploy. |
| Connection timeout SMTP | Coba port 587 dengan secure:false, atau pastikan hosting mengizinkan koneksi keluar SMTP. |
console.log("[v0] ...") untuk membantu melacak error pengiriman.