# Otomasi Email ERP: Memicu Email Transaksional dari Event Bisnis

> Cara saya membangun lapisan otomasi email yang andal dan didukung queue untuk ERP custom menggunakan NestJS EventEmitter2, BullMQ, dan Nodemailer—dengan template Handlebars dan logika retry.

URL: https://www.matthewswong.com/id/blog/erp-email-automation/

- Author: Matthews Wong (https://www.matthewswong.com/id/about/)
- Published: 2025-06-10
- Updated: 2025-06-10
- Category: ERP

Aplikasi bisnis tanpa notifikasi email itu menjengkelkan. Dalam ERP custom yang saya bangun sebagai konsultan ERP lepas, event bisnis penting seharusnya memberi tahu orang-orang yang relevan secara otomatis. Pendekatan naif mengirim email langsung di dalam metode service berhasil sampai tidak berhasil. Post ini menjelaskan sistem email yang terpisah dan didukung queue yang saya bangun.

## Arsitektur: Event-Driven dengan Queue

Prinsip desain inti adalah pemisahan: logika bisnis seharusnya tidak tahu tentang pengiriman email. Service memancarkan event dan melanjutkan. Listener terpisah mengantrekan pekerjaan email. Worker email memproses secara asinkron dengan retry jika gagal.

### NestJS EventEmitter2 sebagai Event Bus

NestJS memiliki modul EventEmitter bawaan berdasarkan EventEmitter2. Service bisnis memancarkan event yang diketik setelah transaksi inti di-commit. Event listener di modul email berlangganan event-event ini dan mengantrekan pekerjaan email yang sesuai.

### BullMQ untuk Pemrosesan Job yang Andal

BullMQ adalah job queue berbasis Redis untuk Node.js. Job disimpan di Redis sehingga bertahan saat aplikasi restart. Setiap job memiliki logika retry yang dapat dikonfigurasi. Job yang gagal berpindah ke failed queue di mana mereka dapat diperiksa dan dicoba ulang.

> Gunakan fitur deduplication job BullMQ (opsi 'jobId') untuk email yang hanya boleh dikirim sekali per objek bisnis. Set jobId ke 'invoice-due-[invoiceId]'—jika pengingat diantrekan dua kali, BullMQ hanya memproses sekali. Ini mencegah duplikat email.

## Template Email dengan Handlebars

Setiap jenis email memiliki template Handlebars yang sesuai. Template dikompilasi sekali saat inisialisasi modul dan di-cache. Helper template menangani format tanggal Indonesia, format Rupiah, dan pluralisasi.

### Nodemailer: Transport SMTP

Nodemailer menangani pengiriman SMTP. Transporter dibuat sekali di processor untuk menggunakan kembali connection pool. Untuk produksi, saya menggunakan SMTP relay khusus yang dikonfigurasi melalui environment variable.

> **Uji Pengiriman Email di Staging**

> Selalu gunakan mail catcher (Mailhog atau Mailpit) di lingkungan lokal dan staging—jangan pernah routing email staging ke alamat nyata. Di Docker Compose, tambahkan service mailhog dan arahkan pengaturan SMTP ke sana.

## Melacak Email yang Terkirim

Setiap email yang terkirim dicatat ke tabel email_logs di Postgres: penerima, subjek, jenis event, entitas terkait, timestamp pengiriman, dan job ID BullMQ. Ini menyediakan audit trail untuk kepatuhan dan debugging.

## Email Terjadwal: Pengingat Faktur Jatuh Tempo

Pengingat faktur jatuh tempo dijadwalkan: cron job harian query faktur yang jatuh tempo dalam 7 hari dan 1 hari yang belum dibayar dan belum mendapat pengingat. Pendekatan ini idempoten—pemeriksaan email_logs mencegah pengiriman duplikat.

## Pemantauan dan Alerting

BullMQ mengekspos metrik queue melalui API-nya. Saya mengekspos sebagai metrik Prometheus dan men-scrape dengan stack Grafana saya. Alert muncul ketika failed queue melebihi ambang batas. Dashboard menampilkan tren throughput email untuk perencanaan kapasitas.

## Sumber & Bacaan Lanjutan

- BullMQ — Dokumentasi — https://docs.bullmq.io/
- Nodemailer — Tentang — https://nodemailer.com/about/
- NestJS — Queues — https://docs.nestjs.com/techniques/queues

> **Key takeaway:** Otomasi email ERP paling baik ketika business logic tidak pernah memanggil layanan email secara langsung. Pengajuan cuti yang disetujui menulis sebuah event, lalu worker terpisah merender dan mengirim pesannya. Pemisahan ini mencegah panggilan SMTP yang gagal membatalkan transaksi yang sudah disetujui, dan membuat pengiriman bisa diulang tanpa menyentuh kode bisnis sama sekali.

## Source links

- https://docs.bullmq.io/
- https://nodemailer.com/about/
- https://docs.nestjs.com/techniques/queues

## FAQ

### Mengapa menggunakan queue (BullMQ) alih-alih mengirim email langsung di dalam logika bisnis?

Mengirim email langsung di dalam metode service menggabungkan pengiriman email dengan transaksi inti, sehingga gangguan SMTP bisa membuat operasi bisnis gagal. Dengan BullMQ yang didukung Redis, job email disimpan dan di-retry secara independen, artinya kegagalan SMTP sementara tidak pernah membatalkan atau memblokir event bisnis yang sedang berjalan.

### Bagaimana sistem mencegah email duplikat untuk event bisnis yang sama?

Fitur deduplication job BullMQ digunakan dengan menetapkan jobId yang deterministik (misalnya, 'invoice-due-{invoiceId}') saat mengantrekan job. Jika job yang sama diantrekan dua kali, BullMQ hanya memprosesnya sekali. Untuk pengingat terjadwal, ada pemeriksaan tambahan ke tabel email_logs untuk memastikan pengingat tidak dikirim ulang ke faktur yang sudah dinotifikasi baru-baru ini.

### Bagaimana template email dikelola, dan mengapa Handlebars dipilih?

Setiap jenis email memiliki template Handlebars (.hbs) tersendiri yang menghasilkan isi HTML. Template dikompilasi sekali saat inisialisasi modul dan di-cache. Helper template menangani format lokal seperti tanggal Indonesia dan format Rupiah. Dengan menyimpan layout di file .hbs, desainer bisa memperbarui tampilan email tanpa menyentuh kode TypeScript.

### Bagaimana email terjadwal seperti pengingat faktur jatuh tempo dipicu?

Cron job harian menggunakan modul @nestjs/schedule di NestJS menjalankan query untuk faktur yang jatuh tempo dalam 7 hari atau 1 hari, belum dibayar, dan belum mendapat pengingat baru-baru ini. Untuk setiap faktur yang memenuhi syarat, job pengingat BullMQ diantrekan. Cron harian ini idempoten—menjalankannya beberapa kali tidak menghasilkan pengingat duplikat karena pemeriksaan email_logs mencegah pengiriman ulang.

### Bagaimana pipeline email dipantau di produksi?

BullMQ mengekspos metrik queue melalui API-nya, yang diubah menjadi metrik Prometheus melalui middleware NestJS kustom dan di-scrape oleh stack Grafana/Prometheus. Alert muncul ketika jumlah failed queue melebihi ambang batas yang dikonfigurasi. Setiap email yang terkirim juga dicatat ke tabel email_logs di Postgres, menyediakan audit trail untuk kepatuhan dan debugging.

---

- HTML version: https://www.matthewswong.com/id/blog/erp-email-automation/
- English: https://www.matthewswong.com/en/blog/erp-email-automation/
- Site index for agents: https://www.matthewswong.com/llms.txt
- Sitemap: https://www.matthewswong.com/sitemap.xml
- API description (OpenAPI): https://www.matthewswong.com/openapi.json
