[{"data":1,"prerenderedAt":385},["ShallowReactive",2],{"search-en":3,"content-en-developer\u002Fexternal-reputation-feedback":4,"surround-en-\u002Fdeveloper\u002Fexternal-reputation-feedback":376},[],{"id":5,"title":6,"body":7,"description":368,"extension":369,"meta":370,"navigation":371,"path":372,"seo":373,"stem":374,"__hash__":375},"content_en\u002F3.developer\u002F37.external-reputation-feedback.md","External reputation feedback",{"type":8,"value":9,"toc":362},"minimark",[10,14,18,23,44,47,61,64,93,104,118,121,155,169,176,208,212,229,240,245,264,271,314,320,327,345,358],[11,12,6],"h1",{"id":13},"external-reputation-feedback",[15,16,17],"p",{},"Owlat's Delivery health page compares its own complaint signal with reputation\ndata reported by mailbox providers. Provider data is delayed and sampled; use it\nas evidence alongside SMTP outcomes, not as a real-time delivery guarantee.",[19,20,22],"h2",{"id":21},"google-postmaster-tools","Google Postmaster Tools",[15,24,25,26,30,31,35,36,43],{},"Google's API requires OAuth 2.0 authorization from a user who can read the\nauthentication domain. A DNS check performed by Owlat does ",[27,28,29],"strong",{},"not"," grant that\nGoogle account access. Register and verify the DKIM ",[32,33,34],"code",{},"d="," domain or SPF\nReturn-Path domain in ",[37,38,42],"a",{"href":39,"rel":40},"https:\u002F\u002Fpostmaster.google.com\u002F",[41],"nofollow","Postmaster Tools",", then\ncreate an OAuth client with the Postmaster Tools API enabled.",[15,45,46],{},"Request only these read scopes:",[48,49,50,56],"ul",{},[51,52,53],"li",{},[32,54,55],{},"https:\u002F\u002Fwww.googleapis.com\u002Fauth\u002Fpostmaster.domain",[51,57,58],{},[32,59,60],{},"https:\u002F\u002Fwww.googleapis.com\u002Fauth\u002Fpostmaster.traffic.readonly",[15,62,63],{},"Generate an offline refresh token for the Google user and configure all three\nMTA variables together:",[65,66,71],"pre",{"className":67,"code":68,"language":69,"meta":70,"style":70},"language-dotenv shiki shiki-themes github-light github-dark-dimmed","GOOGLE_POSTMASTER_CLIENT_ID=...\nGOOGLE_POSTMASTER_CLIENT_SECRET=...\nGOOGLE_POSTMASTER_REFRESH_TOKEN=...\n","dotenv","",[32,72,73,81,87],{"__ignoreMap":70},[74,75,78],"span",{"class":76,"line":77},"line",1,[74,79,80],{},"GOOGLE_POSTMASTER_CLIENT_ID=...\n",[74,82,84],{"class":76,"line":83},2,[74,85,86],{},"GOOGLE_POSTMASTER_CLIENT_SECRET=...\n",[74,88,90],{"class":76,"line":89},3,[74,91,92],{},"GOOGLE_POSTMASTER_REFRESH_TOKEN=...\n",[15,94,95,96,99,100,103],{},"Restart the MTA. The leader queries the v2 ",[32,97,98],{},"domainStats"," resource for the\npreceding seven UTC dates hourly because Google commonly publishes data after a\ndelay. A persisted, bounded domain cursor eventually covers accounts with more\ndomains without allowing one run to grow without limit. The collector also has\na distributed overlap lease, a wall-clock budget, one refresh-on-401 attempt,\nand bounded ",[32,101,102],{},"Retry-After","\u002Ftransient-error retries.",[15,105,106,107,110,111,114,115,117],{},"The refresh token stays in the MTA environment, the access token stays in Redis\nfor less than its provider-declared lifetime, and neither is sent to Convex,\nlogs, Prometheus, or the browser. Before querying statistics or creating any\nper-domain cursor or receipt, the MTA asks the signed Convex endpoint whether\nthat exact domain is currently verified in Owlat. The response contains only\n",[32,108,109],{},"accepted_authorized"," or ",[32,112,113],{},"ignored_unowned","; it exposes no tenant record.\nAuthorization probes and observations bypass generic raw-webhook audit storage,\nand the MTA never puts them in its generic dead-letter queue. A failed delivery\nleaves the domain page uncheckpointed, so the next bounded sweep safely retries\nit. Only an ",[32,116,109],{}," observation creates a receipt. A persistent\ngeneration index lets each completed discovery cycle remove cursor and receipt\nstate for domains Google no longer lists, including across MTA restarts; cleanup\nis capped per run and never scans the Redis keyspace. No per-domain Postmaster\nmetric is exported: the dashboard consumes the structured Convex aggregate.\nOwlat retains that daily aggregate for 90 days and deletes it when the sending\ndomain is removed; an unverified or deleted domain replay is acknowledged\nwithout retaining its name or payload.",[15,119,120],{},"Owlat collects, per verified domain per UTC day:",[48,122,123,129,142,148],{},[51,124,125,128],{},[32,126,127],{},"SPAM_RATE"," — the share of delivered mail Gmail users reported as spam.",[51,130,131,134,135,134,138,141],{},[32,132,133],{},"SPF_SUCCESS_RATE",", ",[32,136,137],{},"DKIM_SUCCESS_RATE",[32,139,140],{},"DMARC_SUCCESS_RATE"," — the share of\ntraffic that authenticated, as Google measured it rather than as our own DNS\ncheck predicts.",[51,143,144,147],{},[32,145,146],{},"DELIVERY_ERROR_RATE"," plus a best-effort per-category breakdown (rate\nlimiting, suspected spam, bad DMARC policy, and so on).",[51,149,150,151,154],{},"The v2 ",[27,152,153],{},"Compliance Status"," verdict: each check's pass\u002Ffail, stored with the\ncheck name Google reported. A check name Owlat has no guidance for is kept\nand rendered generically rather than dropped.",[15,156,157,158,161,162,165,166,168],{},"Google may omit a metric when traffic is too low. ",[32,159,160],{},"No data"," is not a zero spam\nrate, and a partial day is normal — a metric that is missing is simply absent\nfrom the stored row. The current v2 ",[32,163,164],{},"StandardMetric"," contract does\n",[27,167,29],{}," expose the v1 domain-reputation, IP-reputation, sample-IP, or spam-rate\nconfidence-bound fields. Owlat marks those reputation details unavailable; it\ndoes not call v1 with incompatible v2 scopes or infer ratings from another\nmetric. If Google adds reputation metrics to v2, Owlat can add them against\nthat published contract.",[15,170,171,172,175],{},"Postmaster Tools is ",[27,173,174],{},"additive only",". A deployment with no Google account\nconnected sends exactly the same mail: the collector returns early, nothing is\nwritten, nothing errors, and the Delivery page shows a \"not connected\"\naffordance explaining that connecting raises measurement confidence. Failing\ncompliance checks surface as actionable cards on the Delivery page that name\nthe check and the remedy, never as a raw API field.",[15,177,178,179,184,185,190,191,184,196,201,202,207],{},"Sources: ",[37,180,183],{"href":181,"rel":182},"https:\u002F\u002Fdevelopers.google.com\u002Fworkspace\u002Fgmail\u002Fpostmaster\u002Fguides\u002Fsetup",[41],"Google API setup and OAuth scopes",",\n",[37,186,189],{"href":187,"rel":188},"https:\u002F\u002Fdevelopers.google.com\u002Fworkspace\u002Fgmail\u002Fpostmaster\u002Fguides\u002Fsetup-authentication-domain",[41],"authentication-domain setup",",\nthe ",[37,192,195],{"href":193,"rel":194},"https:\u002F\u002Fdevelopers.google.com\u002Fworkspace\u002Fgmail\u002Fpostmaster\u002Fguides\u002Fmigration-v2",[41],"v1-to-v2 migration guide",[37,197,200],{"href":198,"rel":199},"https:\u002F\u002Fdevelopers.google.com\u002Fworkspace\u002Fgmail\u002Fpostmaster\u002Freference\u002Frest\u002Fv2\u002Fdomains.domainStats\u002Fquery",[41],"v2 domain statistics query",",\nand ",[37,203,206],{"href":204,"rel":205},"https:\u002F\u002Fdevelopers.google.com\u002Fworkspace\u002Fgmail\u002Fpostmaster\u002Freference\u002Frest\u002Fv2\u002FMetricDefinition",[41],"v2 standard metrics",".",[19,209,211],{"id":210},"microsoft-snds-and-jmrp","Microsoft SNDS and JMRP",[15,213,214,215,220,221,224,225,228],{},"Microsoft's ",[37,216,219],{"href":217,"rel":218},"https:\u002F\u002Fsubstrate.office.com\u002Fip-domain-management-snds\u002Fsnds",[41],"Smart Network Data Services","\nis IP-oriented. Sign in with a Microsoft account, request access to every public\noutbound IP you control, and complete the portal's authorization process. Then\nuse ",[27,222,223],{},"View Data"," and ",[27,226,227],{},"View IP Status"," to monitor unusual behavior and\nreputation.",[15,230,231,232,235,236,239],{},"In the same portal, enroll those IPs in the ",[27,233,234],{},"Junk Mail Reporting Program"," and\nsend reports to a monitored abuse mailbox. JMRP reports are complaint evidence:\nprocess them promptly through the existing feedback\u002Fsuppression flow and never\nre-mail a complaining recipient. Owlat needs no new plumbing for them — JMRP\nreports are RFC 5965 ARF, so they land in the same feedback processor as every\nother ISP's complaints, attributed to the original send by its signed VERP\nreturn path. Microsoft frequently omits the standard recipient fields and\ncarries the complaining address only in ",[32,237,238],{},"X-HmXmrOriginalRecipient"," on the\nre-attached original, which the processor reads as a last resort.",[241,242,244],"h3",{"id":243},"importing-the-snds-data-feed","Importing the SNDS data feed",[15,246,247,248,251,252,255,256,259,260,263],{},"Microsoft's July 2026 portal announcement replaced the legacy\n",[32,249,250],{},"sendersupport.olc.protection.outlook.com\u002Fsnds\u002F"," links with per-account\n",[27,253,254],{},"Automated Data Access"," URLs. Generate one per registered IP range and set\nthem as ",[32,257,258],{},"SNDS_DATA_FEED_URLS"," (comma- or whitespace-separated, ",[32,261,262],{},"https"," only).\nKeep them secret: each URL is a bearer capability to your SNDS data.",[15,265,266,267,270],{},"Owlat polls those feeds every six hours and stores one row per sending IP per\nUTC day — the complaint-rate ",[27,268,269],{},"band",", the filter result, spam-trap hits and the\nday's volume counters — with 90-day retention. The feed reports activity in\nsub-day windows; a day folds them together, summing counters and keeping the\nworst band and filter result of the day. Registered ranges overlap, so a day\nreported by two of your feeds folds into that same single row instead of two\ncompeting ones.",[15,272,273,274,276,277,280,281,284,285,288,289,134,292,295,296,299,300,303,304,307,308,310,311,313],{},"SNDS reports a complaint-rate ",[27,275,269],{},", not a rate, so Owlat stores and reasons\nabout the band. ",[32,278,279],{},"0.1% - \u003C 0.2%"," is never turned into ",[32,282,283],{},"0.0015",": that would invent\na precision Microsoft never published, and every downstream decision would then\ncompare a fabricated number. A band spelling Owlat does not recognise is stored\nas ",[32,286,287],{},"unknown",", which holds the ramp rather than moving it. The parser matches the\ncolumn against Microsoft's documented spellings whole — ",[32,290,291],{},"\u003C 0.1%",[32,293,294],{},"> 0.9%"," and\none-band-wide ranges such as ",[32,297,298],{},"0.3% - \u003C 0.4%"," — and never reads a number out of\ntext it does not otherwise recognise. So a bound that is not a band edge\n(",[32,301,302],{},"\u003C 0.5%"," spans five bands), a widened range (",[32,305,306],{},"0% - \u003C 0.9%"," spans nine), a\nlocalized decimal separator and a prose rewording are all ",[32,309,287],{}," rather than\nguessed at. The feed is internet-supplied, ",[32,312,291],{}," is the only band that can\njustify speeding the ramp up, and the one direction the parser must never fail\nis towards \"cleaner than measured\".",[15,315,316,317,319],{},"The gate breaches from ",[32,318,279],{}," upwards, matching the complaint gate it\nsits beside, and also on any red filter result or any spam-trap hit. Each poll\nand each gate read is bounded — the feed body is capped while it streams, the\nnumber of (IP, day) observations per poll is capped, and both the ingest and the\ngate work newest-day-first so a same-day breach can never fall off the end of a\ncap — a day that was never stored would otherwise read later as a day with\nnothing wrong in it.\nA read that hits its cap is marked low-confidence, so a partial window can slow\nthe ramp but never justify speeding it up.",[15,321,322,323,326],{},"Enrollment is optional, and its absence is a supported configuration rather than\nan incomplete setup. With no feed configured the poller returns immediately —\nno request, no row, no error — and the Microsoft ramp leans on the outcomes of\nits own sends instead (bounce, deferral and complaint rates, plus seed placement\nat Outlook), dwelling twice as long before it advances and capping one phase\nlower. If you declare\nyour sending addresses in ",[32,324,325],{},"MTA_IP_POOLS",", feed rows for any other address are\ndropped, since an SNDS key can cover a whole registered range.",[15,328,329,331,332,336,337,340,341,344],{},[32,330,325],{}," also scopes the gate's read, not just the ingest. With a pool\ndeclared the gate reads only the days recorded against those addresses. With no\npool declared it reads the window whole but marks it ",[333,334,335],"em",{},"unattributed",": a clean\nband in a shared registered range may belong to another sender, so it stays\nusable for slowing the ramp and can never speed it up. Concretely: a clean\nunattributed window ",[333,338,339],{},"holds"," rather than passing, because a pass is what grows\nthe clean streak an increase is spent from — and a spam-trap hit that is the\n",[333,342,343],{},"only"," breaching evidence in such a window holds too. Evidence that may be a\nneighbour's moves the ramp in neither direction. Breaches are unchanged: a red\nfilter result or a band at or above the breach band still fails the gate whether\nor not the window is attributed, because a problem inside our own registered\nrange is still ours to answer. Every verdict derived from an unattributed window\nsays so in its reason and names the remedy. Declaring your pool is\ntherefore the cheapest way to raise the Microsoft cell's measurement confidence\n— and, like every other external signal here, not declaring it slows the ramp\nand does nothing else.",[15,346,347,348,352,353,207],{},"Microsoft sources: ",[37,349,351],{"href":217,"rel":350},[41],"SNDS portal and enrollment","\nand ",[37,354,357],{"href":355,"rel":356},"https:\u002F\u002Fsendersupport.olc.protection.outlook.com\u002Fpm\u002Ftroubleshooting",[41],"Outlook.com sender troubleshooting",[359,360,361],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":70,"searchDepth":83,"depth":83,"links":363},[364,365],{"id":21,"depth":83,"text":22},{"id":210,"depth":83,"text":211,"children":366},[367],{"id":243,"depth":89,"text":244},"Connect Google Postmaster Tools and enroll in Microsoft SNDS and JMRP.","md",{},true,"\u002Fdeveloper\u002Fexternal-reputation-feedback",{"title":6,"description":368},"3.developer\u002F37.external-reputation-feedback","Rvlu9ZPN40w8LP8uDDFER_egkVeu_XGSOSUBlmYB4tI",[377,381],{"title":378,"path":379,"stem":380,"children":-1},"Setup CLI & Installer","\u002Fdeveloper\u002Fsetup-cli","3.developer\u002F36.setup-cli",{"title":382,"path":383,"stem":384,"children":-1},"DNS blocklist recovery","\u002Fdeveloper\u002Fdnsbl-delisting","3.developer\u002F38.dnsbl-delisting",1786915100307]