Uncategorized

ImapFlow: Cara Simpel Mark All Emails as Read dalam Satu Pipeline

Tutorial resolve mark all emails as read dengan ImapFlow di Node.js — pakai fetchOne() dan messageFlagsAdd() yang benar, bukan loop kosong.
Featured image

ImapFlow: Cara Simpel "Mark All Emails as Read" dalam Satu Pipeline

Kategori: Programming & Development
Slug: imapflow-mark-all-read-email
Tags: ImapFlow, Node.js, IMAP, email automation, backend
Meta title: Cara Mark All Emails as Read dengan ImapFlow Tanpa Ribet
Meta description: Tutorial singkat resolve mark all emails as read dengan ImapFlow di Node.js — pakai fetchOne() dan messageFlagsAdd() yang benar, bukan loop kosong.


Saat bekerja dengan IMAP di Node.js menggunakan library ImapFlow, ada satu kebutuhan yang terlihat sederhana tapi sering bikin developer bingung: menandai semua email sebagai sudah dibaca dalam satu langkah.

Dokumentasi ImapFlow tidak selalu jelas soal ini. Method yang seharusnya justru nggak ada, loop yang mestinya mengembalikan pesan tiba-tiba kosong, dan timeout yang datang tanpa peringatan.

Artikel ini langsung ke solusi.


Kenapa Masalah Ini Sering Terjadi

Ada tiga error yang paling sering muncul saat developer mencoba mark all as read dengan ImapFlow:

Method tidak ditemukan
messageAddFlags() atau store() — keduanya nggak ada di API ImapFlow. Kalau kamu pakai ini, operasi langsung gagal sebelum mulai.

Loop fetch mengembalikan array kosong
for await (const msg of client.fetch()) — di kondisi tertentu, terutama saat mailbox sedang di-lock, loop ini bisa banget возвращать nol hasil padahal ada ribuan email di inbox.

Timeout saat fetch dalam jumlah besar
IMAP server punya batasan seberapa cepat client boleh fetching. Untuk inbox dengan ribuan pesan, operasi standar bisa timeout sebelum selesai.


Solusinya: fetchOne() + messageFlagsAdd()

Intinya ada dua method yang perlu dipakai bersama:

Yang Sering Dipakai Yang Benar
client.messageAddFlags() client.messageFlagsAdd()
client.store() client.fetchOne() per email

messageFlagsAdd() dan fetchOne() — ini dua method yang bekerja dengan benar untuk use case mark all as read.


Kenapa fetchOne(), Bukan fetch()?

Ini yang sering bikin bingung.

fetch() dengan loop for await...of itu powerful, tapi dia mengembalikan iterable. Di kondisi tertentu — terutama kalau mailbox sedang di-lock oleh operasi lain — loop ini bisa silently mengembalikan nol hasil tanpa error. Artinya kamu nggak dapet satu email pun, tapi juga nggak dapet pemberitahuan bahwa sesuatu salah.

fetchOne() berbeda. Dia mengambil satu pesan berdasarkan sequence number, jauh lebih stabil, dan lebih predictable. Untuk pipeline yang butuh commit semua email tanpa exception, fetchOne() adalah pilihan yang lebih safe.


Step-by-Step yang Berhasil

1. Connect ke Server

const { ImapFlow } = require('imapflow')

const client = new ImapFlow({
  host: 'mail.example.com',
  port: 993,
  secure: true,
  auth: {
    user: '[email protected]',
    pass: 'your-password'
  }
})

await client.connect()

2. Dapat Total Pesan di Inbox

const mailbox = await client.status('INBOX', { messages: true })
const totalMessages = mailbox.messages

console.log(`Total email: ${totalMessages}`)

status() itu ringan dan nggak mengunci mailbox — aman untuk dijalankan sebelum operasi bulk.

3. Kumpulkan UID dengan fetchOne()

Ini step yang paling kritikal. Loop dari email pertama sampai terakhir, ambil UID-nya satu per satu:

const uids = []

for (let i = 1; i <= totalMessages; i++) {
  const msg = await client.fetchOne(i, { uid: true })
  if (msg && msg.uid) {
    uids.push(msg.uid)
  }
}

console.log(`UID terkumpul: ${uids.length}`)

Kenapa nggak langsung aja pake fetch() dan filter yang $seen: false?

Karena ada kondisi di mana flag belum tersimpan di server IMAP saat kamu fetch. Dengan loop fetchOne() satu per satu, kamu dapat UID yang sebenarnya dari hasil server — bukan dari cache lokal.

4. Tandai Semua sebagai Read

if (uids.length > 0) {
  await client.messageFlagsAdd(uids, '\\Seen')
  console.log(`Berhasil menandai ${uids.length} email sebagai read`)
}

\\Seen itu flag IMAP standar untuk email yang sudah dibaca. Tinggal lempar array UID dan flag ini, server IMAP yang tangani sisanya.

5. Cleanup

await client.logout()

Contoh Kode Lengkap

const { ImapFlow } = require('imapflow')

async function markAllEmailsAsRead() {
  const client = new ImapFlow({
    host: 'mail.example.com',
    port: 993,
    secure: true,
    auth: {
      user: '[email protected]',
      pass: 'your-password'
    }
  })

  try {
    await client.connect()

    const mailbox = await client.status('INBOX', { messages: true })
    const totalMessages = mailbox.messages
    console.log(`Total email: ${totalMessages}`)

    const uids = []
    for (let i = 1; i <= totalMessages; i++) {
      const msg = await client.fetchOne(i, { uid: true })
      if (msg && msg.uid) {
        uids.push(msg.uid)
      }
    }

    console.log(`UID terkumpul: ${uids.length}`)

    if (uids.length > 0) {
      await client.messageFlagsAdd(uids, '\\Seen')
      console.log(`Berhasil menandai ${uids.length} email sebagai read`)
    }

  } catch (error) {
    console.error('Error:', error.message)
  } finally {
    await client.logout()
  }
}

markAllEmailsAsRead()

Urutan Operasi yang Benar

Pastikan pipeline kamu mengikuti urutan ini:

  1. Connect ke IMAP server
  2. Get mailbox status — dapat total pesan tanpa mengunci
  3. Loop dengan fetchOne() — ambil UID tiap email satu per satu
  4. Panggil messageFlagsAdd() — lempar array UID + flag \\Seen
  5. Logout

Jangan pernah skip langkah logout. Koneksi IMAP yang nggak di-close dengan benar bisa bikin server memblok akun kamu untuk sementara.


Tips Biar Nggak Timeout

Untuk inbox dengan ribuan email, ada tiga hal yang bikin perbedaan:

Pakai lock kalau perlu
getMailboxLock() diperlukan kalau kamu operasi yang mengubah state mailbox bersamaan dengan proses lain. Untuk mark all as read yang sequential seperti ini, lock dari fetchOne() loop biasanya sudah cukup.

Timeout yang cukup
ImapFlow punya timeout default untuk setiap operasi. Untuk inbox besar, set timeout lebih longgar dari default:

const client = new ImapFlow({
  // ... auth config
  timeout: 120_000  // 2 menit untuk inbox besar
})

Chunk kalau perlu
Kalau server IMAP kamu lambat atau timeout masih terjadi, pecah jadi chunk 500-1000 UID per batch:

const chunkSize = 500
for (let i = 0; i < uids.length; i += chunkSize) {
  const chunk = uids.slice(i, i + chunkSize)
  await client.messageFlagsAdd(chunk, '\\Seen')
  console.log(`Batch ${Math.floor(i/chunkSize) + 1} done`)
}

Ringkasan

Masalah mark all as read dengan ImapFlow sebenarnya cukup straightforward kalau kamu tahu dua method ini:

  • fetchOne() — ambil UID satu per satu, lebih reliable dari fetch() dengan loop
  • messageFlagsAdd() — mark email sebagai read dengan array UID

Dua-duanya ada di API ImapFlow, bukan凑出来的 workaround. Pakai kombinasi ini, pipeline kamu akan jalan lebih stabil dibanding pakai cara lain yang terlihat lebih singkat tapi sering gagal diam-diam.

Semoga membantu developer lain yang mengalami masalah serupa!

5 Views
0 Likes
0 Shares
Estimasi waktu baca: 5 menit

Tentang Penulis

System API

System API

Digital Marketing Strategist
Fullstack Engineer
Business Consultant

Profesional dengan pengalaman 15+ tahun dalam digital marketing, fullstack development, dan konsultasi bisnis. Fokus membantu bisnis Indonesia membangun sistem yang efisien, scalable, dan berdampak langsung ke pertumbuhan bisnis.

Pelajari Tentang Kami
RD
Rama Digital

Spesialis integrasi sistem marketing dan modernisasi aplikasi untuk pebisnis Indonesia. Membantu UMKM dan perusahaan scale dengan teknologi modern.

Contact

  • [email protected]
  • +62 858-0332-7994
  • Park 23 Creative Hub, 3rd Floor
    Jl. Kediri, Tuban, Kuta, Badung
    Bali 80361
  • 9:00 - 18:00 WIB

Mulai Project

Siap optimasi bisnis Anda dengan teknologi modern? Konsultasi gratis sekarang.

Konsultasi Gratis