Üç çağrı, ve kurulacak hiçbir şey yok
Arayüzün tamamı https://grabmail.io/api/v1 altındaki üç uç nokta, artı diğerlerinin size hazır olarak verdiği ekler için tek bir adrestir. Posta kutusu oluştur diye bir çağrı yoktur, ve bu yokluk bir eksiklik değildir: bir adres, posta ona ulaştığında var olmaya başlar, bu yüzden böyle bir çağrının yapacağı hiçbir şey yoktur.
| Çağrı | Neyi yanıtlar | Ne geçirirsiniz |
|---|---|---|
GET /mailbox | Bir adreste bekleyen her şey, en yeniden en eskiye. | address, isteğe bağlı olarak da limit ve before |
GET /message/{id} | Bir mesajın tamamı: düz metin bölümü, HTML bölümü ve URL'si zaten hazırlanmış her ek. | mailbox |
DELETE /message/{id} | Saklama süresinin dolmasını beklemek yerine onu hemen kaldırır. | mailbox |
GET /attachment/{id} | Bir dosyanın baytları, tam olarak geldiği haliyle. | mailbox |
Her yanıt, her hata dahil, JSON'dur. Her zaman damgası RFC 3339 biçiminde UTC'dir. Mesaj kimlikleri opaktır: onları olduğu gibi geri verin, asla parçalarına ayırmayın.
İlk çağrı, ve boş bir adresin verdiği yanıt
Bir isim seçin, arkasına genel alan adlarından birini koyun ve okuyun. Önce var olması gereken hiçbir şey yoktur, ve sormakla da hiçbir şey oluşturulmaz.
$ curl -sG https://grabmail.io/api/v1/mailbox \
--data-urlencode "address=k7fq2m@grabmail.io"{
"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"
}
]
}Beş alan, ve bunlardan ikisi göründüğünden daha ilginçtir:
count- Bu yanıtta kaç mesaj olduğu — posta kutusunun kaç tane tuttuğu değil.
limitgeçirdiğiniz an, bunlar iki farklı sayı olur. next- Bundan sonraki sayfanın imleci, ya da sonrasında hiçbir şey yoksa
null. Az önce size verilen son mesajın kimliğidir, bu yüzden sayfalamayı keşfetmenin ekstra bir çağrıya mal olmamasının nedeni de budur. messages- Listenin kendisi, en yeniden en eskiye. Her girdi zaten şunları taşır:
subject,from,date,seen, metnin kısa birpreview'i, bir HTML bölümü olup olmadığı ve kaç ek olduğu. alias- Buraya teslimat yapan ama bu adres hakkında hiçbir şey ele vermeyen ikinci bir adres. Gerçek adres yerine bunu bir forma verin; sonunda onu bu hizmete yazan kim olursa olsun, boş bir posta kutusu bulur.
address- Adresin anlaşıldığı hâli, küçük harfe çevrilmiş ve kırpılmış olarak. Adresi parçalardan oluşturuyorsanız, gönderdiğinizle karşılaştırın.
İlk ellinin ötesini okumak
Bir çağrı, varsayılan olarak en fazla elli, en üst sınırda ise iki yüz mesajla yanıt verir. Yoğun bir catch-all adres bir öğleden sonrada ikisini de geçer, ve okuyucuların yanlış tahmin ettiği kısım bundan sonra gelendir — çünkü bu bir sayfa numarası değildir.
limit- Bu çağrıda kaç tanenin döndürüleceği, 1 ile 200 arası. Aralık dışı değerler reddedilmek yerine sınırlanır, bu yüzden
limit=5000size sessizce 200 verir. before- Zaten elinizde olan en eski mesajın kimliği. Ondan sonrakileri alırsınız. Önceki yanıtın
nextalanına ne koyduysa onu geri geçirin. nextnull, posta kutusunun sonuna ulaştığınız anlamına gelir. Bu, güvenilir tek liste sonu sinyalidir: kısa bir sayfa bu anlama gelmez, çünkü bir sayfa yalnızca sunucu öyle dediğinde kısadır.
limit bir yanıtı üst sınırlar, next o yanıtın nerede durduğunu adlandırır, ve before ondan sonrakileri ister.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
donenext null olmadığı sürece döngüye devam edin, ve posta kutusunun tamamına sahip olursunuz, ne kadar büyümüş olursa olsun. Her çağrı bir ofset değil, bir indeks üzerinde aralık okumasıdır, bu yüzden bininci sayfa da ilkinin maliyetine mal olur.
Başka bir posta kutusundan gelen ya da o zamandan beri süresi dolmuş bir imleç bir hata değildir: boş bir sayfa ve next: null alırsınız. Bu doğru yanıttır — bunun yerine en yeni sayfayı tekrarlamak, bir betiğe zaten işlediği postayı verirdi — ama bunun anlamı, bayat bir imlecin tam olarak liste sonu gibi görünmesidir.
Bir mesajı açmak, ve buna gerek olmadığı zaman
Listeden gelen kimlik ile teslim edildiği posta kutusu birlikte size mesajın kendisini verir. İkisi de zorunludur: bir gelen kutusundan sızan bir kimlik başka birini okumak için kullanılamaz, çünkü her arama adrese göre de kapsam sınırlıdır.
$ curl -sG https://grabmail.io/api/v1/message/3QK7ZB5M9WVXR2HD4TNFJ0PC6A \
--data-urlencode "mailbox=k7fq2m@grabmail.io"{
"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- Düz metin bölümü. Varsa bunu ayrıştırın: kararlıdır, hiçbir biçimlendirme taşımaz, ve içindeki altı haneli bir kod, altı haneli bir koddur.
html- HTML bölümü, ya da gönderen bunu göndermediyse
null. Onay bağlantıları çoğu zaman yalnızca burada bulunur. attachments- Dosya başına bir girdi, her birinin çekilecek URL'si zaten hazırlanmış olarak. Hiç yoksa
nulldeğil, boş bir liste. expires_at- Bu mesajın ne zaman silineceği,
dateile aynı RFC 3339 biçiminde. Bunu hesaplamak yerine okuyun — saklama süresi, dışarıdan emin olabileceğiniz bir ayar değildir.
Çoğu zaman bu çağrıyı tamamen atlayabilirsiniz. Listeleme zaten konuyu, göndereni, tarihi ve metnin kısa bir önizlemesini döndürür, ki bu, bir mesajın beklediğiniz mesaj olmadığına karar vermek için yeterlidir. Bir posta kutusundaki her mesajı, hiçbirini istemediğinizi öğrenmek için çekmek, bir betiğin yavaşlamasının en yaygın yoludur.
Bir dosyayı dışarı almak
Her ek kendi url'sini taşır, ve döngüyü yazmadan önce bilinmeye değer ayrıntı, bunun mutlak bir adres değil, bu kaynak üzerinde bir yol olduğudur — içinde mailbox parametresi zaten vardır. Önüne kaynağı koyun, çekin; geçirecek ya da yetkilendirecek başka hiçbir şey yoktur.
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"
doneGönderen dosyayı ne olarak etiketlemiş olursa olsun, her zaman Content-Disposition: attachment ile application/octet-stream yanıtı verir. Bu bilinçlidir — bir yabancının text/html'ini olduğu gibi yansıtmak, bir ekin bu kaynak üzerinde bir sayfa olarak çalışmasına izin verirdi — bu yüzden türle ilgilenen bir betik bunu, bir talimat değil veri olarak durduğu mesaj JSON'undan okur.
Dosyalar dahil mesajın tamamı 5 MB ile sınırlıdır. Base64 bir ikiliyle işini bitirdikten sonra bu tavanın ne anlama geldiği kendi başına bir konudur, ve bunun için ekler hakkında bir rehber vardır.
Tek değil, iki hız bütçesi
Bilinmeye değer ve gözden kaçması kolay olan kısım şu: bir adresi listelemek ve ondan okumak ayrı ayrı ölçülür, çünkü ikisi aynı risk değildir. Bir adresi bilen herkes onun listesini yoklayabilir; bir mesajı okumak ise bir kimlik gerektirir, ve tahmin edilecek hiçbir şey yoktur.
| Ne çağırıyorsunuz | Bütçe | Pratikte anlamı |
|---|---|---|
GET /mailbox | Adres başına saniyede bir istek | Amaçlanan yoklama ritmi budur, ve bu hızda asla kısıtlanmaz. Daha hızlısı reddedilir, ve zaten işe yaramazdı. |
GET /message/{id}, GET /attachment/{id}, DELETE | Adres başına çok daha cömert | Bir sayfa mesajı, aralarında durmadan tek seferde boşaltın. Bir arayüzün, bir yoklamanın çalıştığı saniyede bir mesaj açabilmesinin nedeni budur. |
| Her şey, toplamda | İstemci başına dakikada 1200 istek | Saniyede bir yoklanan yirmi adres — herhangi bir gerçek otomasyonun rahatlıkla ötesinde, ve on bin adreste dolaşan tek bir sunucuya konan bir dur işareti. |
Bunlardan herhangi birini aşarsanız, bekleme süresi saniye cinsinden Retry-After başlığında olacak şekilde 429 alırsınız. Kendi uydurduğunuz bir sayıyla geri çekilmek yerine buna uyun: sunucu size tam olarak ne zaman evet diyeceğini söylüyordur.
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
}Henüz gelmemiş bir mesajı nasıl bekleyeceğiniz — bir yeniden deneme sayısı değil bir son tarih, ve o geçtiğinde ne yapılacağı — doğrulama akışlarını test etme rehberinin konusudur. Oradaki döngü, zamanlanmış bir işin de ihtiyaç duyduğu döngüyle aynıdır.
Silmek, ve hepsinin altındaki taban
İşi biten bir mesaj, saklama süresini beklemek yerine hemen gidebilir. Çağrı idempotenttir: aynı kimliği iki kez silmek her iki seferde de 200 yanıtı verir, bu yüzden yeniden denenen bir istek asla bir başarısızlık gibi görünmez.
$ curl -s -X DELETE -G https://grabmail.io/api/v1/message/3QK7ZB5M9WVXR2HD4TNFJ0PC6A \
--data-urlencode "mailbox=k7fq2m@grabmail.io"- Aradığınızı bulduğunuzda silin
- Bir mesajı işleyip yerinde bırakan bir betik, gördüklerinin kendi listesini tutmadığı sürece bir sonraki çalıştırmada onu yeniden işler. Silmek, daha ucuz bir muhasebedir.
- Gizlilik için buna güvenmeyin
- Varış ile silinme arasında, adresi bilen herkes onu okumuş olabilir. Silmek pencereyi kapatır; onu geri almaz.
- Her şey ne olursa olsun 5 günde gider
- Okunmuş ya da okunmamış, silinmiş ya da silinmemiş, bir mesaj vardığından 5 gün sonra kaybolur. Bu bir ayar değil, kesin bir sınırdır, ve hiçbir parametre onu uzatmaz.
Dallanılacak kısaltmalar, ve asla okunmaması gereken alan
Her başarısızlık, aynı iki alana sahip JSON'dur. error, kararlı, makine tarafından okunabilir bir kısaltmadır; message ise insanlar içindir ve her an yeniden ifade edilebilir. İkincisine göre dallanmak, bir betiğin hiçbir şeyin değişmediği bir günde bozulmasının yoludur.
| Durum ve kısaltma | Ne oldu | Bir betiğin ne yapması gerektiği |
|---|---|---|
400 invalid_address | Adres eksik, ya da bir adrese benzemiyor. | Hemen başarısız olun. Hiçbir yeniden deneme miktarı bir yazım hatasını düzeltmez. |
400 bad_cursor | before bir mesaj kimliği değil. | Hemen başarısız olun, ve kendi oluşturduğunuz bir şey yerine next'i geri geçirdiğinizi kontrol edin. |
404 unknown_domain | O alan adı burada barındırılmıyor. | Hemen başarısız olun. Kendi alan adınızda bu, MX kaydıdır — bkz. bir alan adı bağlamak. |
404 not_found | O posta kutusunda böyle bir mesaj yok, ya da saklama süresini geçmiş. | Bunu kaybolmuş sayın. Yanlış posta kutusuna karşı okunan geçerli bir kimlik için de aynısını alırsınız. |
429 rate_limited | Yukarıdaki bütçelerden biri. | Retry-After saniye kadar uyuyun ve devam edin. Bunu asla başarısız bir çalıştırma saymayın. |
Bir adresi her saat boşaltan bir iş
Parçaları bir araya getirince zamanlanmış bir iş kısa olur. Bu iş, bir adreste bekleyen her mesajı alır, JSON olarak diske yazar ve siler — bu yüzden bir sonraki çalıştırma boş bir posta kutusundan başlar ve aynı mesajı asla iki kez işleyemez.
#!/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
done17 * * * * /usr/local/bin/drain.shAdını koymaya değer dört özellik var, çünkü çalışır bırakabileceğiniz bir işi izlemeniz gereken bir işten ayıran şey tam olarak bunlar:
- İki kez çalıştırmak güvenlidir. Aynı anda başlatılan iki kopya, aynı işi farklı bir sırayla yapar ve aynı mesajları siler; ikincisi boş bir posta kutusu bulur ve durur.
- Silmeden önce yazar. Disk doluysa ya da süreç öldürülürse, mesaj bir sonraki çalıştırmada hâlâ posta kutusundadır. Ters sıra, tam da önemli olduğu gün postayı kaybeder.
- Okumaz, boşaltır. Her mesaj diske güvenle yazılır yazılmaz gittiği için, bir sonraki listeleme bir sonraki iki yüzü döndürür — bu yüzden çalıştırmalar arasında dört yüz mesaj alan bir posta kutusu, en yeni elliye kadar değil, tamamen boşaltılır.
- Yüksek sesle başarısız olur. Cron'un size çıktıyı göndermesini sağlayan şey, sıfır olmayan bir çıkış kodudur. Kendi hatalarını yutan bir iş, bir aydır bozuk olan bir iştir.
Bu API'nin sizin için yapmayacağı şeyler
Yapmadığı dört şey var, her biri kasıtlı ve hiçbiri daha sonra eklenmeyecek. Bunları, sessizce yarı çalışan bir betikten keşfetmek yerine şimdi tasarımınıza dahil etmek daha iyidir:
- Asla göndermez
- Yalnızca alır. Bir mesajı hatta koyan bir uç nokta yoktur, bu yüzden burada hiçbir şey sahibi olmadığınız bir adresten göndermek için kullanılamaz.
- Asla itmez
- Ne webhook ne de geri çağırma vardır: siz sorarsınız, o yanıtlar. Posta gelene kadar bloke olmayı tercih eden bir yapay zeka ajanının bunun yerine MCP üzerinden
wait_for_message'ı vardır — bkz. ajanlar için rehber. - Asla aramaz
- Bir gönderen ya da konu için sorgu parametresi yoktur. Filtreleme sizin tarafınızda, listeleme üzerinden gerçekleşir — listelemenin bir önizleme taşımasının nedenlerinden biri de budur.
- Genel bir alan adında asla kimlik doğrulamaz
- Adresi bilen herkes posta kutusunu okur. Adres, sırrın tamamıdır, bu yüzden ona öyle davranın: onu asla bir müşterinin isminden türetmeyin, ve yüksek sesle okunmasından rahatsız olacağınız hiçbir şeyi paylaşılan bir alan adına yönlendirmeyin.
Sonuncusunun yanıtı, sahibi olduğunuz bir alan adıdır. MX'ini smtp.grabmail.io'e yöneltin, üzerindeki her adres öğrenilecek ikinci bir API ve döndürülecek bir anahtar olmadan aynı üç uç nokta üzerinden yanıt verir — ve talep üzerine, yalnızca bir bearer anahtarının açabileceği şekilde kapatılabilir. Bir alan adı bağlamak tek bir DNS kaydı gerektirir.
10 smtp.grabmail.io
Çalışır bırakmadan önce
Siz izlemeden çalışacak bir işte kontrol etmeye değer altı şey:
- Adres başına saniyede birden hızlı yoklamayın, ve beklemeniz söylendiğinde
Retry-After'a uyun. next'i sona kadar takip edin, tek bir çağrının posta kutusunun tamamı olduğunu varsaymak yerine.- Durum koduna ve
error'a göre dallanın, aslamessage'a göre değil. - Saklamanız gereken her şeyi silmeden önce yazın, ve 5 günün oynatamayacağınız bir taban olduğunu unutmayın.
- Çıkardığınız her şeyi kendi şablonunuza sabitleyin. Yalın bir altı haneli örüntü, önce gelen bir yılı, bir fiyatı ya da bir sipariş numarasını seve seve eşleştirir.
- Kontrol ettiğiniz bir alan adında olmadığı sürece adresin genel olduğunu varsayın, ve önemli olan her şeyi öyle olan bir tanesine koyun.
Hiçbiri bir hesap gerektirmez. Genel alan adlarını aştığınızda değişen şey adresteki alan adıdır — yukarıdaki üç çağrı tam olarak oldukları gibi kalır.
Sorular
Bir API anahtarına ihtiyacım var mı?
Hayır. Genel alan adlarında hesap, jeton ya da kaydolunacak hiçbir şey yoktur, ve buraya yönlendirdiğiniz bir alan adı da aynı uç noktalarda anahtar olmadan yanıt verir. Tek istisna, talep üzerine kapattığımız ve bir Authorization: Bearer başlığıyla okunan bir alan adıdır.
Ne kadar hızlı yoklayabilirim?
Listeleme için adres başına saniyede bir, ki bu amaçlanan ritimdir ve asla kısıtlanmaz. Bir mesajı ya da eki okumak ayrı ve çok daha cömert ölçülür, bu yüzden bir sayfa mesajı tek seferde boşaltabilirsiniz. Her şey birlikte istemci başına dakikada 1200 istekle sınırlıdır.
Posta kutusunun tamamını okuduğumu nasıl anlarım?
next, null döndüğünde. Bunu kısa bir sayfadan çıkarmayın: bir sayfanın ne olduğuna sunucu karar verir, ve limit'ten daha kısa bir sayfa, tek başına son anlamına gelmez.
Bunu bir tarayıcıdan çağırabilir miyim?
Evet. Yanıtlar Access-Control-Allow-Origin: * taşır, bu yüzden herhangi bir kaynaktaki bir sayfa, arada sizin bir proxy'niz olmadan uç noktaları doğrudan çağırabilir. Buradaki yetkilendirme asla bir çerez değildir, bu yüzden bu kadar açmanın bir bedeli yoktur.
Süresi dolmuş bir mesajı istersem ne olur?
Hiç var olmamış bir kimlik için olduğu gibi, tam olarak not_found ile 404. Okunmuş olsun olmasın, her şey vardığından 5 gün sonra silinir, ve hiçbir parametre bunu uzatmaz.
Posta geldiğinde bir webhook alabilir miyim?
Hayır — REST API sor-ve-yanıtla biçimindedir, geri çağırma yoktur. İstediğiniz şey mesaj gelene kadar bloke olan bir kodsa, MCP sunucusunda tam olarak bunu yapan ve ajanlar için tasarlanmış wait_for_message vardır.
Üretimde genel bir adres kullanmak güvenli mi?
Yalnızca bir yabancının okumasından rahatsız olmayacağınız şeyler için. Adresi bilen herkes, tıpkı site üzerinden olduğu gibi API üzerinden de posta kutusunu okuyabilir. Başka her şey için, sahibi olduğunuz bir alan adını buraya yönlendirin — çağrılar değişmez.
Hiç açmadığım bir mesaj neden okunmuş görünüyor?
Çünkü bir şey onu açtı. Bir mesajı API üzerinden okumak seen bayrağını ayarlar, ve bu bayrak o adrese bakan herkesle paylaşılır. Aynı posta kutusunu izleyen bir betik ile bir kişi birbirini sürekli şaşırtmaya devam eder, bu yüzden seen yerine işlediğiniz kimliklere göre filtreleyin.
Mesajları silmek zorunda mıyım?
Hayır — her şey 5 gün sonra kendiliğinden süresi dolar. Yine de zamanlanmış bir işte silmek yapmaya değer, çünkü boşaltılmış bir posta kutusu, zaten işlediğinizin mümkün olan en basit kaydıdır.


