API & otomatisasi

API Email Sekali Pakai: Otomatisasi Inbox lewat Skrip

Tiga endpoint, tanpa key dan tanpa akun: cukup bagi sebuah skrip untuk membuka sebuah alamat, membaca apa yang masuk ke dalamnya, dan membereskan jejaknya sendiri. Inilah keseluruhan loop-nya — dua kuota laju yang menentukan seberapa cepat Anda boleh melaju, dan satu tenggat yang tidak bisa digeser.

  • Menengah
  • 22 menit baca
Ban berjalan berwarna abu-abu yang digerakkan oleh roda gigi biru, membawa dua amplop biru menuju sebuah baki abu-abu yang terbuka

Tiga panggilan, dan tidak ada yang perlu disiapkan

Keseluruhan antarmukanya adalah tiga endpoint di bawah https://grabmail.io/api/v1, ditambah satu alamat untuk lampiran yang sudah disediakan siap pakai oleh endpoint lainnya. Tidak ada panggilan buat kotak surat, dan ketiadaannya bukan sebuah kelalaian: sebuah alamat mulai ada begitu surat tiba di sana, jadi tidak ada yang bisa dikerjakan oleh panggilan semacam itu.

PanggilanYang dijawabnyaYang Anda kirim
GET /mailboxSemua yang menunggu di sebuah alamat, yang terbaru lebih dulu.address, dan secara opsional limit serta before
GET /message/{id}Satu pesan secara lengkap: bagian plain-text, bagian HTML, dan setiap lampiran dengan URL yang sudah jadi.mailbox
DELETE /message/{id}Menghapusnya sekarang juga, alih-alih menunggu jendela retensi habis.mailbox
GET /attachment/{id}Byte dari satu file, persis seperti saat tiba.mailbox

Setiap jawaban berbentuk JSON, termasuk setiap error. Setiap waktu memakai UTC dalam bentuk RFC 3339. Id pesan bersifat buram: kembalikan begitu saja, jangan pernah membongkarnya.

Panggilan pertama, dan jawaban dari sebuah alamat kosong

Pilih sebuah nama, tempelkan salah satu domain publik di belakangnya, lalu baca. Tidak ada yang perlu ada duluan, dan tidak ada yang tercipta hanya karena bertanya.

shell
$ curl -sG https://grabmail.io/api/v1/mailbox \
  --data-urlencode "address=k7fq2m@grabmail.io"
jawaban
{
  "address": "k7fq2m@grabmail.io",
  "alias": "q4v8n2mt7xkd@example.net",
  "count": 1,
  "next": null,
  "messages": [
    {
      "id": "3QK7ZB5M9WVXR2HD4TNFJ0PC6A",
      "from": "no-reply@example.com",
      "from_name": "Example",
      "subject": "Your verification code",
      "preview": "Your code is 481920. It expires in 10 minutes.",
      "has_html": false,
      "date": "2026-08-29T09:14:02Z",
      "seen": false,
      "attachments": 0,
      "expires_at": "2026-09-03T09:14:02Z"
    }
  ]
}

Lima field, dan dua di antaranya lebih menarik daripada kelihatannya:

count
Berapa banyak pesan ada di jawaban ini — bukan berapa banyak yang disimpan kotak suratnya. Begitu Anda mengirim limit, keduanya jadi dua angka yang berbeda.
next
Cursor untuk halaman setelah ini, atau null kalau tidak ada lagi setelahnya. Ini adalah id dari pesan terakhir yang baru saja Anda terima, itulah sebabnya paging tidak membutuhkan panggilan tambahan untuk mengetahuinya.
messages
Daftarnya sendiri, yang terbaru lebih dulu. Setiap entri sudah membawa subject, from, date, seen, preview singkat dari teksnya, apakah ada bagian HTML, dan berapa banyak lampirannya.
alias
Alamat kedua yang mengantar ke sini juga, tapi tidak membocorkan apa pun soal alamat yang ini. Berikan ini ke formulir, bukan alamat aslinya; siapa pun yang akhirnya memilikinya dan mengetikkannya ke layanan ini akan menemukan kotak surat yang kosong.
address
Alamat sebagaimana dipahami sistem: sudah diubah ke huruf kecil dan di-trim. Bandingkan dengan yang Anda kirim kalau Anda menyusun alamatnya dari beberapa bagian.

Membaca melewati lima puluh pesan pertama

Satu panggilan menjawab dengan paling banyak lima puluh pesan secara default, dan dua ratus di titik paling maksimalnya. Sebuah catch-all yang sibuk bisa melewati keduanya dalam satu sore, dan bagian yang sering ditebak salah oleh pembaca adalah apa yang terjadi selanjutnya — karena ini bukan nomor halaman.

limit
Berapa banyak yang dikembalikan dalam panggilan ini, 1 sampai 200. Nilai di luar jangkauan itu dipangkas, bukan ditolak, jadi limit=5000 diam-diam memberi Anda 200.
before
Id dari pesan paling lama yang sudah Anda pegang. Anda akan mendapat yang setelahnya. Kirim balik apa pun yang ditaruh jawaban sebelumnya di next.
next
null berarti Anda sudah mencapai akhir kotak surat. Ini satu-satunya sinyal akhir-daftar yang bisa diandalkan: halaman yang pendek bukanlah sinyal itu, karena sebuah halaman hanya pendek kalau server yang memutuskannya begitu.
hasil satu panggilanyang dibawa balik before=nextterbaruterlamaBukan nomor halaman — posisi dalam daftar terurut.
limit membatasi satu jawaban, next menamai di mana jawaban itu berhenti, dan before meminta apa yang ada setelahnya.
menyusuri seluruh kotak surat, halaman terlama di akhir
ADDR="k7fq2m@grabmail.io"
CURSOR=""

while :; do
  PAGE=$(curl -fsG https://grabmail.io/api/v1/mailbox \
           --data-urlencode "address=$ADDR" \
           --data-urlencode "limit=200" \
           ${CURSOR:+--data-urlencode "before=$CURSOR"})

  printf '%s' "$PAGE" | jq -c '.messages[]'

  CURSOR=$(printf '%s' "$PAGE" | jq -r '.next // empty')
  [ -n "$CURSOR" ] || break
  sleep 1
done

Buat loop selama next bukan null, dan Anda akan mendapat seluruh isi kotak surat, sebesar apa pun ia bertambah. Setiap panggilan adalah pembacaan rentang pada sebuah index, bukan offset, jadi halaman keseribu berbiaya sama dengan halaman pertama.

Sebuah cursor dari kotak surat lain, atau yang sudah kedaluwarsa, bukanlah sebuah error: Anda akan mendapat halaman kosong dan next: null. Itu jawaban yang benar — mengulang halaman terbaru sebagai gantinya justru akan memberi skrip itu surat yang sudah pernah diprosesnya — tapi ini juga berarti sebuah cursor basi akan terlihat persis seperti akhir daftar.

Membuka satu pesan, dan kapan Anda tidak perlu melakukannya

Id dari daftar tadi, ditambah kotak surat tempat pesan itu dikirim, memberi Anda pesannya sendiri. Keduanya wajib: sebuah id yang bocor dari satu kotak masuk tidak bisa dipakai untuk membaca kotak masuk lain, karena setiap pencarian juga dibatasi lingkupnya pada alamat tersebut.

shell
$ curl -sG https://grabmail.io/api/v1/message/3QK7ZB5M9WVXR2HD4TNFJ0PC6A \
  --data-urlencode "mailbox=k7fq2m@grabmail.io"
jawaban
{
  "id": "3QK7ZB5M9WVXR2HD4TNFJ0PC6A",
  "from": "no-reply@example.com",
  "to": "k7fq2m@grabmail.io",
  "subject": "Your verification code",
  "date": "2026-08-29T09:14:02Z",
  "expires_at": "2026-09-03T09:14:02Z",
  "text": "Your code is 481920. It expires in 10 minutes.",
  "html": null,
  "attachments": []
}
text
Bagian plain-text-nya. Urai (parse) bagian ini kalau tersedia: bentuknya stabil, tidak membawa markup apa pun, dan sebuah kode enam digit di dalamnya ya kode enam digit itu sendiri.
html
Bagian HTML-nya, atau null kalau pengirim tidak menyertakannya. Tautan konfirmasi sering kali hanya ada di sini.
attachments
Satu entri per file, masing-masing dengan URL untuk mengambilnya yang sudah jadi. Daftar kosong, bukan null, kalau tidak ada satu pun.
expires_at
Kapan pesan ini akan dihapus, dalam bentuk RFC 3339 yang sama seperti date. Baca nilai ini alih-alih menghitungnya sendiri — jendela retensi bukan sebuah pengaturan yang bisa Anda pastikan dari luar.

Sangat sering Anda bisa melewatkan panggilan ini sama sekali. Daftarnya sudah mengembalikan subjek, pengirim, tanggal, dan preview singkat dari teksnya, yang sudah cukup untuk memutuskan bahwa sebuah pesan bukan yang sedang Anda tunggu. Mengambil setiap pesan dalam sebuah kotak surat hanya untuk mendapati Anda tidak menginginkan satu pun dari mereka adalah cara paling umum sebuah skrip menjadi lambat.

Mengambil sebuah file

Setiap lampiran membawa url-nya sendiri, dan hal yang penting diketahui sebelum menulis loop-nya: itu adalah sebuah path pada origin ini, bukan alamat lengkap — dengan parameter mailbox yang sudah ada di dalamnya. Tinggal tambahkan origin-nya di depan, ambil, dan tidak ada lagi yang perlu dikirim atau diotorisasi.

shell
ADDR="k7fq2m@grabmail.io"
ID="3QK7ZB5M9WVXR2HD4TNFJ0PC6A"

curl -fsG https://grabmail.io/api/v1/message/$ID \
  --data-urlencode "mailbox=$ADDR" \
| jq -r '.attachments[] | "\(.url)\t\(.filename)"' \
| while IFS=$'\t' read -r path name; do
    curl -fs "https://grabmail.io$path" -o "$name"
  done

Ia selalu menjawab dengan application/octet-stream beserta Content-Disposition: attachment, apa pun label yang diberikan pengirim pada file itu. Ini disengaja — mengembalikan text/html milik orang asing apa adanya akan membuat sebuah lampiran bisa berjalan sebagai halaman di origin ini — jadi skrip yang peduli pada tipe filenya membaca itu dari JSON pesannya, di mana ia adalah data, bukan instruksi.

Keseluruhan pesan, berikut semua filenya, dibatasi hingga 5 MB. Apa arti batas itu setelah base64 selesai mengolah sebuah file biner adalah topik tersendiri, dan ada panduan tentang lampiran untuk itu.

Dua kuota laju, bukan satu

Inilah bagian yang penting diketahui dan mudah terlewat: daftar isi sebuah alamat dan pembacaan dari alamat itu dijatah secara terpisah, karena keduanya bukan risiko yang sama. Siapa pun yang tahu sebuah alamat bisa melakukan polling pada daftarnya; membaca sebuah pesan membutuhkan id, dan tidak ada yang bisa ditebak.

Yang Anda panggilKuotaArtinya dalam praktik
GET /mailboxSatu request per detik, per alamatRitme polling yang memang dimaksudkan, dan tidak pernah diperlambat pada kecepatan itu. Lebih cepat dari itu akan ditolak, dan toh tidak akan membantu.
GET /message/{id}, GET /attachment/{id}, DELETEJauh lebih longgar, per alamatKuras satu halaman pesan sekaligus tanpa jeda di antaranya. Inilah sebabnya sebuah antarmuka bisa membuka sebuah pesan di detik yang sama saat sebuah polling baru saja berjalan.
Semuanya, dijumlahkan1200 request per menit, per clientDua puluh alamat yang di-polling sekali per detik — jauh melampaui otomatisasi nyata mana pun, dan sekaligus jadi rem bagi satu host yang mencoba menyusuri sepuluh ribu alamat.

Melewati salah satu dari itu, Anda akan mendapat 429 dengan waktu tunggunya, dalam detik, di header Retry-After. Patuhi angka itu, bukannya mundur dengan angka karangan sendiri: itu adalah server yang memberi tahu Anda persis kapan ia akan bilang ya.

tidur selama yang diminta, tidak lebih lama dari itu
read_box() {
  local wait
  while :; do
    BODY=$(curl -s -D /tmp/gm.h -G https://grabmail.io/api/v1/mailbox \
             --data-urlencode "address=$1")
    grep -qi '^HTTP/[0-9.]* 429' /tmp/gm.h || { printf '%s' "$BODY"; return 0; }
    wait=$(awk 'tolower($1) == "retry-after:" { print $2 + 0 }' /tmp/gm.h)
    sleep "${wait:-1}"
  done
}

Bagaimana menunggu sebuah pesan yang belum tiba — sebuah tenggat waktu, bukan hitungan percobaan ulang, dan apa yang harus dilakukan saat tenggat itu terlewati — adalah topik dari panduan menguji alur verifikasi. Loop di sana adalah loop yang sama yang dibutuhkan sebuah job terjadwal.

Menghapus, dan batas dasar di bawah semuanya

Pesan yang sudah selesai Anda pakai bisa langsung dihapus, tidak perlu menunggu jendela retensinya habis. Panggilan ini idempoten: menghapus id yang sama dua kali tetap menjawab 200 kedua-duanya, jadi sebuah request yang dicoba ulang tidak pernah terlihat seperti kegagalan.

shell
$ curl -s -X DELETE -G https://grabmail.io/api/v1/message/3QK7ZB5M9WVXR2HD4TNFJ0PC6A \
  --data-urlencode "mailbox=k7fq2m@grabmail.io"
Hapus begitu Anda sudah dapat yang dicari
Skrip yang memproses sebuah pesan lalu membiarkannya tetap di sana akan memprosesnya lagi pada run berikutnya, kecuali skrip itu menyimpan daftarnya sendiri tentang apa yang sudah pernah dilihatnya. Menghapus adalah cara pembukuan yang lebih murah.
Jangan mengandalkannya untuk privasi
Antara kedatangan dan penghapusan, siapa pun yang tahu alamatnya bisa saja sudah membacanya. Menghapus menutup jendela itu; itu tidak membatalkan apa yang sudah terjadi.
Semuanya lenyap di hari ke-5 apa pun yang terjadi
Dibaca atau tidak, dihapus atau tidak, sebuah pesan lenyap 5 hari setelah kedatangannya. Ini batas keras, bukan sebuah pengaturan, dan tidak ada parameter yang bisa memperpanjangnya.

Slug yang jadi dasar percabangan, dan field yang jangan pernah dibaca

Setiap kegagalan berbentuk JSON dengan dua field yang sama. error adalah slug stabil yang bisa dibaca mesin; message untuk manusia dan bisa diubah kata-katanya kapan saja. Menjadikan yang kedua sebagai dasar percabangan adalah cara sebuah skrip menjadi rusak pada hari ketika tidak ada apa pun yang berubah.

Status dan slugYang terjadiYang harus dilakukan skrip
400 invalid_addressAlamatnya tidak ada, atau bentuknya bukan seperti sebuah alamat.Gagalkan seketika. Percobaan ulang sebanyak apa pun tidak akan memperbaiki salah ketik.
400 bad_cursorbefore bukan sebuah id pesan.Gagalkan seketika, dan periksa apakah Anda mengirim balik next, bukan sesuatu yang Anda susun sendiri.
404 unknown_domainDomain itu tidak di-hosting di sini.Gagalkan seketika. Pada domain milik Anda sendiri, ini soal record MX-nya — lihat menghubungkan domain.
404 not_foundTidak ada pesan seperti itu di kotak surat tersebut, atau ia sudah melewati jendela retensinya.Perlakukan sebagai sudah lenyap. Ini juga yang akan Anda dapat untuk sebuah id valid yang dibaca dengan kotak surat yang salah.
429 rate_limitedSalah satu dari kuota di atas.Tidur selama Retry-After detik lalu lanjutkan. Jangan pernah menghitungnya sebagai run yang gagal.

Job yang menguras sebuah alamat tiap jam

Satukan semua bagiannya dan sebuah job terjadwal jadi singkat. Yang ini mengambil setiap pesan yang menunggu di sebuah alamat, menuliskannya ke disk sebagai JSON, lalu menghapusnya — jadi run berikutnya selalu mulai dari kotak surat kosong dan tidak akan pernah memproses pesan yang sama dua kali.

drain.sh
#!/usr/bin/env bash
set -euo pipefail

ADDR="orders@example.com"
OUT="/var/lib/mailsink"
API="https://grabmail.io/api/v1"

mkdir -p "$OUT"

while :; do
  page=$(curl -fsG "$API/mailbox" \
           --data-urlencode "address=$ADDR" \
           --data-urlencode "limit=200")

  ids=$(printf '%s' "$page" | jq -r '.messages[].id')
  [ -n "$ids" ] || break

  for id in $ids; do
    curl -fsG "$API/message/$id" \
      --data-urlencode "mailbox=$ADDR" > "$OUT/$id.json"
    curl -fs -X DELETE -G "$API/message/$id" \
      --data-urlencode "mailbox=$ADDR" > /dev/null
  done

  sleep 1
done
crontab
17 * * * * /usr/local/bin/drain.sh

Ada empat sifat yang layak disebutkan, karena itulah yang membedakan job yang bisa dibiarkan berjalan sendiri dari job yang harus terus diawasi:

  1. Aman dijalankan dua kali. Dua salinan yang dijalankan bersamaan mengerjakan pekerjaan yang sama dengan urutan berbeda dan menghapus pesan yang sama; yang kedua akan menemukan kotak surat kosong dan berhenti.
  2. Ia menulis sebelum menghapus. Kalau disknya penuh atau prosesnya di-kill, pesannya masih ada di kotak surat pada run berikutnya. Urutan sebaliknya akan kehilangan surat justru di hari saat itu benar-benar penting.
  3. Ia menguras, bukan sekadar membaca. Karena setiap pesan langsung pergi begitu aman tersimpan di disk, daftar berikutnya akan mengembalikan dua ratus pesan selanjutnya — jadi kotak surat yang menerima empat ratus pesan di antara dua run akan dikosongkan sepenuhnya, bukan cuma disisakan lima puluh yang terbaru.
  4. Ia gagal dengan berisik. Exit dengan kode bukan nol itulah yang membuat cron mengirimkan output-nya kepada Anda. Job yang menelan errornya sendiri adalah job yang sudah rusak selama sebulan.

Yang tidak akan dilakukan API ini untuk Anda

Empat hal yang tidak dilakukannya, masing-masing memang disengaja dan tidak satu pun akan ditambahkan nanti. Lebih baik merancang sistem Anda dengan mempertimbangkan ini sekarang daripada menemukannya lewat sebuah skrip yang diam-diam sudah setengah tidak berfungsi dengan benar:

Ia tidak pernah mengirim
Hanya menerima. Tidak ada endpoint yang mengirimkan pesan ke jaringan, itulah sebabnya tidak ada apa pun di sini yang bisa dipakai untuk mengirim dari alamat yang bukan milik Anda.
Ia tidak pernah mendorong
Tidak ada webhook dan tidak ada callback: Anda bertanya, ia menjawab. AI agent yang lebih memilih blocking sampai suratnya tiba punya wait_for_message lewat MCP sebagai gantinya — lihat panduan untuk agent.
Ia tidak pernah mencari
Tidak ada parameter query untuk pengirim atau subjek. Penyaringan terjadi di sisi Anda, di atas daftarnya — salah satu alasan kenapa daftar itu membawa preview.
Ia tidak pernah mengautentikasi, di domain publik
Siapa pun yang tahu alamatnya bisa membaca kotak suratnya. Alamat itu adalah keseluruhan rahasianya, jadi perlakukan begitu: jangan pernah menurunkannya dari nama seorang pelanggan, dan jangan pernah arahkan apa pun yang keberatan Anda bacakan keras-keras ke sebuah domain publik yang dipakai bersama.

Jawaban untuk yang terakhir itu adalah sebuah domain milik Anda sendiri. Arahkan MX-nya ke smtp.grabmail.io dan setiap alamat di domain itu akan terjawab lewat tiga endpoint yang sama ini, tanpa API kedua yang perlu dipelajari dan tanpa key yang perlu dirotasi — dan, atas permintaan, bisa ditutup sehingga hanya bearer key yang membukanya. Menghubungkan domain hanya butuh satu record DNS.

10 smtp.grabmail.io

Sebelum Anda membiarkannya berjalan sendiri

Enam hal yang layak diperiksa pada sebuah job yang akan berjalan tanpa Anda awasi:

  1. Jangan polling lebih cepat dari sekali per detik per alamat, dan patuhi Retry-After saat Anda diminta menunggu.
  2. Ikuti next sampai habis, alih-alih menganggap satu panggilan sudah mewakili seluruh kotak surat.
  3. Buat percabangan berdasarkan kode status dan error, jangan pernah berdasarkan message.
  4. Tulis apa pun yang perlu Anda simpan sebelum menghapusnya, dan ingat bahwa 5 hari adalah batas dasar yang tidak bisa digeser.
  5. Kaitkan apa pun yang Anda ekstrak dengan template Anda sendiri. Pola enam digit polos akan dengan senang hati cocok dengan sebuah tahun, harga, atau nomor pesanan yang tiba lebih dulu.
  6. Anggap alamatnya bersifat publik kecuali berada di domain yang Anda kendalikan sendiri, dan taruh apa pun yang penting di domain yang seperti itu.

Tidak satu pun dari ini membutuhkan akun. Kalau Anda sudah melampaui kebutuhan domain publik, yang berubah hanyalah domain di alamatnya — ketiga panggilan di atas tetap persis sama.

Pertanyaan

Apakah saya perlu API key?

Tidak. Pada domain publik tidak ada akun, tidak ada token, dan tidak ada yang perlu didaftarkan, dan sebuah domain yang Anda arahkan ke sini pun menjawab lewat endpoint yang sama tanpa key juga. Satu-satunya pengecualian adalah domain yang sudah kami tutup atas permintaan, yang dibaca dengan header Authorization: Bearer.

Seberapa cepat saya boleh polling?

Sekali per detik per alamat untuk daftarnya, yang memang ritme yang dimaksudkan dan tidak pernah diperlambat. Membaca sebuah pesan atau lampiran dijatah secara terpisah dan jauh lebih longgar, jadi Anda bisa menguras satu halaman pesan sekaligus. Semuanya digabung dibatasi hingga 1200 request per menit per client.

Bagaimana saya tahu kalau sudah membaca seluruh kotak surat?

Ketika next kembali sebagai null. Jangan menyimpulkannya dari sebuah halaman yang pendek: server yang menentukan apa itu sebuah halaman, dan halaman yang lebih pendek dari limit bukan dengan sendirinya berarti akhir.

Bisakah saya memanggil ini dari browser?

Bisa. Setiap jawaban membawa header Access-Control-Allow-Origin: *, jadi sebuah halaman dari origin mana pun bisa memanggil endpoint-endpoint itu langsung tanpa proxy milik Anda di tengah-tengah. Otorisasi di sini tidak pernah berbentuk cookie, jadi membukanya selebar itu tidak ada ruginya.

Apa yang terjadi kalau saya meminta pesan yang sudah kedaluwarsa?

404 dengan not_found, persis seperti untuk id yang memang tidak pernah ada. Semuanya dihapus 5 hari setelah tiba, dibaca ataupun tidak, dan tidak ada parameter yang bisa memperpanjangnya.

Bisakah saya mendapat webhook saat surat tiba?

Tidak — REST API ini bersifat tanya-jawab, tanpa callback. Kalau yang Anda inginkan adalah kode yang blocking sampai pesannya tiba, server MCP punya wait_for_message, yang persis melakukan itu dan memang ditujukan untuk agent.

Amankah memakai alamat publik di production?

Hanya untuk hal-hal yang tidak Anda persoalkan kalau dibaca orang asing. Siapa pun yang tahu alamatnya bisa membaca kotak suratnya, lewat API persis seperti lewat situsnya. Untuk yang lainnya, arahkan sebuah domain milik Anda sendiri ke sini — panggilan-panggilannya tidak berubah.

Kenapa pesan yang belum pernah saya buka muncul sebagai sudah dibaca?

Karena sesuatu sudah membukanya. Membaca sebuah pesan lewat API mengatur flag seen-nya, dan flag itu dibagikan ke semua orang yang melihat alamat tersebut. Sebuah skrip dan seseorang yang memantau kotak surat yang sama akan terus saling mengejutkan, jadi saring berdasarkan id yang sudah Anda tangani, bukan berdasarkan seen.

Apakah saya harus menghapus pesan?

Tidak — semuanya kedaluwarsa dengan sendirinya setelah 5 hari. Menghapus tetap layak dilakukan dalam sebuah job terjadwal, karena kotak surat yang sudah dikosongkan adalah catatan paling sederhana yang mungkin ada tentang apa yang sudah Anda proses.

Coba selagi masih segar

Alamat hanya perlu satu klik, tanpa akun dan tanpa kartu. Semua yang ada di panduan ini langsung berfungsi dengannya.

Selamat datang kembali

Kotak surat dan domain Anda, di satu tempat.