Skip to main content

Email Outcome Calibration

Build an owned accuracy loop by attaching real delivery and bounce outcomes to earlier email-validation decisions. Outcome operations are append-only and charge zero credits. Use separate API keys in production:
  • email:outcomes:write imports evidence but cannot read reports.
  • email:outcomes:read reads aggregate reports but cannot upload addresses.

Automate EmailBison outcomes

Create a revocable, write-only connector URL with an API key carrying email:outcomes:write:
cURL
The response returns webhook_url once. Add that URL in EmailBison and enable only email_sent, email_opened, email_bounced, lead_replied, lead_interested, and lead_unsubscribed. Creating another connector rotates the credential and immediately invalidates the previous URL. email_sent is mandatory because it supplies the denominator for prospective bounce-rate measurement. If other events arrive before any sent event, the connector reports denominator_status=sent_event_missing and all accuracy gates remain fail-closed. GTM APIs stores only the connector-token hash. The webhook accepts only a bounded JSON body, deduplicates retries by EmailBison’s stable scheduled-email ID, and never stores campaign message bodies or arbitrary EmailBison metadata. Known DSN fields are used transiently for bounce classification. Replies become confirmed delivery evidence; opens and sent-with-no-bounce observations remain separate, weaker signals.
cURL
Connector errors include stable codes. connector_unavailable means the account cannot use this connector. Retry connector_status_failed, connector_create_failed, or connector_revoke_failed with bounded backoff. After connector_revoke_failed, treat the existing webhook credential as active until a later revoke request succeeds.

Import outcomes

Each request accepts 1–10,000 outcomes and a body up to 5 MB. source plus external_id is the idempotency key. Include the provider’s enhanced SMTP code and diagnostic text when available; specific DSN evidence takes precedence over a coarse label such as bounce or rejected.
cURL
You can also post an EmailBison-style diagnostics export directly. The importer recognizes email or lead_email, bounce_type, status, smtp_code, action, enhanced_status, bounce_reason, diagnostic, dsn_message, dsn_subject, bounced_at, arrival_date, last_attempt_date, will_retry_until, original_recipient, final_recipient, remote_mta, reporting_mta, dsn_gateway, received_from_mta, and emailbison_lead_id columns. Raw diagnostic text is used for classification but is not persisted as outcome metadata. RFC-native exports can use Action and Status directly. The importer keeps the transport-independent Status code as classification evidence instead of replacing it with the coarse event outcome. Action accepts only failed, delayed, delivered, relayed, or expanded, without regard to case. A different non-empty value rejects that row as invalid_dsn_semantics and cannot create a suppression. Balanced RFC comments are ignored before the action is selected. Comment text cannot supply or override the action, and a malformed comment rejects the row. Action and Status are not redundant. A failed report can keep a 4.x temporary-failure Status after the MTA abandons retries. The importer accepts that standards-defined pair as bounced_soft and does not create a permanent recipient suppression. When a recognized Action is supplied, a non-empty Status must use the RFC 3464 status-code form, such as 5.1.1. The second and third fields cannot have leading zeroes, and an RFC comment can follow the code. Comment text is ignored for classification and cannot add another status code or diagnostic. Malformed structured Status evidence rejects that row as invalid_dsn_semantics and cannot create a suppression. Without an RFC Action, generic vendor status text keeps its existing import behavior. RFC Original-Recipient and Final-Recipient values use rfc822; person@example.com form. When Original-Recipient is supplied, it must match email and can safely correlate a different final address after forwarding. Without it, Final-Recipient must match email. Malformed, foreign-address, and conflicting recipient evidence rejects the row before it can affect suppression or accuracy reports. RFC comments are removed before the address type and mailbox are checked. Comment text cannot supply either value, and malformed comments reject the row. RFC Remote-MTA uses dns; mx.example.com form when the remote system has a DNS name. A valid DNS hostname is bounded provider evidence for the system that issued the diagnostic, and it takes precedence over route aliases and diagnostic prose. Foreign MTA types, malformed hosts, IP literals, and provider lookalikes remain non-attributing evidence and cannot activate a provider-specific rule. RFC comments are removed before the MTA type and hostname are checked. Comment text cannot supply either value, and malformed comments fail closed. RFC Reporting-MTA uses the same typed form and is required in a complete DSN. When Remote-MTA is absent, a valid DNS Reporting-MTA identifies the system that issued the diagnostic and takes precedence over route aliases and prose. When Remote-MTA is supplied, it always controls issuer selection. An invalid or foreign Remote-MTA blocks Reporting-MTA fallback instead of attributing the remote diagnostic to the reporting gateway. RFC DSN-Gateway identifies the gateway that translated a foreign delivery notification. It is not the diagnostic issuer. Remote-MTA or Reporting-MTA still controls attribution when present. Without either issuer field, supplied DSN-Gateway evidence blocks provider inference from route aliases and prose. RFC Received-From-MTA identifies the upstream MTA that handed the message to the reporting MTA. It is not the diagnostic issuer. Remote-MTA or Reporting-MTA still controls attribution when present. Without either issuer field, supplied Received-From-MTA evidence also blocks route-alias and prose provider inference. When occurred_at is absent, RFC Last-Attempt-Date supplies the delivery attempt time. It must use RFC 822 date-time syntax with a numeric +HHMM or -HHMM timezone. Invalid or future-dated values reject that row instead of falling back to import time. An explicit valid occurred_at takes precedence. occurred_at uses RFC 3339 syntax. Lowercase t and z are accepted and normalized to uppercase UTC. Z, +00:00, and -00:00 all identify a UTC instant; -00:00 additionally reports that local-zone provenance is unknown. Fractions through the sixth fractional position are preserved and compared at microsecond precision. Non-zero precision beyond that position is rejected as invalid_timestamp before PostgreSQL can round it; supply the source system’s canonical timestamp at microsecond precision or lower. Leap-second notation such as 23:59:60Z is rejected as invalid_timestamp because the canonical UTC chronology cannot represent the extra second without loss. Supply the source system’s canonical POSIX timestamp instead. RFC Arrival-Date uses the same numeric-timezone syntax and records when the message reached the Reporting MTA. It never replaces occurred_at or Last-Attempt-Date as the outcome time. Malformed or future values reject the row, as does an Arrival-Date later than a supplied valid Last-Attempt-Date. RFC Will-Retry-Until uses the same syntax and is accepted only with Action: delayed. It records the retry horizon, so a future value is valid and never becomes occurred_at. Malformed values, use with any other action, and a deadline before Arrival-Date or Last-Attempt-Date reject the row. For all three RFC date fields, balanced comments are removed before parsing. Comment text cannot supply or replace the timestamp, and malformed comments reject the row through the same date-field error. The weekday is optional. When supplied, it must match the stated local calendar date before timezone conversion. A mismatch rejects the row through the same date-field error and cannot affect suppression freshness. Both +0000 and -0000 identify Universal Time. The -0000 form additionally reports that local-zone provenance is unknown; it is accepted and normalized to the same canonical UTC instant.
cURL
Invalid rows include a zero-based index, stable machine-readable code, and human-readable reason; the response does not repeat their email addresses. Branch on code, do not parse reason, and preserve unknown non-empty future codes. Import request errors use invalid_json, invalid_csv, missing_outcomes, too_many_outcomes, or payload_too_large. Retry outcome_import_failed with the same provider event identities. outcome_suppression_failed means the outcome import did not finish its fail-closed suppression step; retry the same import rather than creating different event identities.

Evidence semantics

Only delivered and confirmed bounced_hard are decision-grade mailbox labels. For RFC DSNs, include the per-recipient action field. failed leaves the specific status and diagnostic in control. delayed means the MTA will keep trying, while delivered, relayed, and expanded do not report a bounce failure and cannot create a recipient suppression. RFC continuation lines are accepted only as CRLF followed by a space or tab. Each legal fold becomes one space before parsing. Bare LF, bare CR, and unindented continuation lines reject structured evidence instead of being treated as field contents. For a typed RFC Diagnostic-Code, comments in parentheses are human-readable context only. The classifier removes them before it reads the diagnostic type or SMTP reply. Comment text cannot create SMTP evidence, and a foreign diagnostic type remains opaque. Untyped vendor diagnostics keep the legacy compatibility parser. Any other supplied non-empty action value is invalid structured evidence. The importer rejects that row instead of ignoring the value or applying its status and diagnostic. Use delivered only for a provider’s final delivery event. A successful API request, queued message, SMTP handoff, or absence of a bounce is not delivery proof. smartlead and webhook rows must include an immutable external_id plus either an RFC 3339 occurred_at or RFC Last-Attempt-Date. This prevents provider retries from changing event meaning and prevents old evidence from becoming fresh at import time. csv and manual rows can omit these fields; their missing timestamp uses import time only when Last-Attempt-Date is also absent. A supplied invalid timestamp is always rejected instead of being replaced with the import time. A recipient reply is accepted as confirmed delivery evidence. Opens and clicks are not: privacy proxies and security scanners can generate them without proving recipient mailbox engagement. Confirmed permanent recipient bounces are added to that tenant’s mailbox suppression list only while the evidence is fresh: mailbox-not-found evidence is reused for 90 days, disabled/inactive mailbox evidence for 14 days, and domain/DNS failure evidence for 24 hours. Older rows remain in calibration but increment stale_suppressions_skipped and require a fresh validation. Expiry never marks an address valid or recommends sending. Explicit complaints and unsubscribes are stored independently as durable contact preferences: they return unknown plus send_recommendation=do_not_send instead of falsely labeling the mailbox invalid. Policy, reputation, and temporary delivery failures are not suppressed. An unqualified DNS error or DNS failure without structured status evidence is retryable because it does not distinguish a missing domain from a temporary resolver outage. Only explicit Null MX, no-mail-route, no-MX, or recipient-domain nonexistence evidence can create a domain/DNS suppression.

Reusing confirmed deliveries

A recent delivered outcome can improve future coverage for the same tenant without another SMTP probe. The reuse gate requires all of the following:
  • the delivery occurred within the previous 30 days;
  • source is csv, smartlead, or webhook and external_id is present;
  • this tenant has an immutable, current-policy validation decision from before the delivery;
  • the latest decision-grade outcome is still delivered; and
  • no tenant hard-bounce suppression exists for the address.
Evidence-backed responses return validation_source=recent_delivery_evidence and charge zero credits. Delivery evidence is never shared between tenants or written into the global validation cache. A manual outcome is retained for calibration but cannot create a positive validation result.

Platform recipient bounce consensus

GTM APIs can conservatively downgrade an otherwise SMTP-accepted recipient when provider-observed message outcomes show recent hard bounces from at least three independent tenants. Each tenant contributes at most one latest vote, every send must follow an immutable current-policy SMTP-accepted decision, and any confirmed reply within the 30-day evidence window vetoes the downgrade. Consensus responses retain smtp_valid=true as raw protocol evidence, return result=risky, validation_source=platform_recipient_bounce_consensus, send_recommendation=do_not_send, and charge zero credits. The function is service-role only and returns no tenant, workspace, message, or event detail. It never labels the recipient permanently invalid.

Read the calibration report

The default window is the previous 90 days. Supply optional strict RFC 3339 start and end values with Z or a numeric UTC offset for a window of at most 366 days. Date-only, zone-less, locale-style, and padded timestamps return invalid_report_timestamp. Repair invalid_report_timestamp, invalid_report_range, or report_range_too_large before retrying. Retry outcome_report_failed with bounded backoff.
cURL
The response contains the original report, a send_observations report, and a gateway_shadow report. The latter measures the latest unique recipient sent through EmailBison and separates:
  • confirmed delivery from replies/interested events;
  • open signals, which may come from proxies or scanners;
  • hard, soft, policy, and unknown bounces;
  • sends matured for seven days without any bounce; and
  • unresolved recent sends that have not yet reached the maturity window.
gateway_shadow evaluates enterprise-gateway inference separately for Proofpoint, Mimecast, Barracuda, Cisco, Sophos, Trend Micro, Fortinet, Broadcom, Hornetsecurity, and an other_gateway fallback. Each gateway/action pair remains in shadow until it has at least 300 decision-grade unique-recipient outcomes, an observed hard-bounce rate no greater than 1%, and a Wilson 95% upper bound no greater than 1%. A passing family never promotes a different gateway family or a different inferred action. The response also includes evidence_readiness. Treat evidence_readiness.market_claim_ready as the only public market-claim signal. It becomes true only when the statistical and provider-breadth claim gates pass and the prospective ledger has at least 300 unique sends, at least 95% validation linkage, and at least 90% outcome resolution. The same denominator gate is also evaluated independently in send_observations.provider_evidence_gates; another provider’s sends cannot satisfy the Microsoft gate. Before promoting a Microsoft SMTP route, require evidence_readiness.microsoft_route_outcome_ready=true. It combines the Microsoft matched-outcome operational gate with the Microsoft-only prospective send gate. It does not replace the separate route-bound controlled canary. Both nested reports expose decision_version. Only predictions created by that exact policy version enter calibration. Sends tied only to a legacy policy stay in the prospective denominator as unmatched, so every decision-changing release must establish fresh linkage and outcome evidence. Claim-grade predictions are read from an append-only ledger with stable decision IDs and timestamps. The operational history table can still be upserted during CSV retries, but those mutations cannot rewrite or backdate accuracy evidence. Older mutable rows are intentionally not backfilled. Matured no-bounce rows contribute only to operational bounce-risk resolution. They never count as confirmed delivery, reusable address evidence, or a claim-grade positive control. A late bounce automatically replaces the inferred no-bounce state because maturity is calculated from the current observation ledger rather than persisted as a delivery outcome. Both reports contain aggregate counts and rates only. Raw email addresses, domains, and MX hosts remain inside the tenant-scoped database join and are never returned. Outcomes use bounded provider segments: Microsoft consumer, authoritative Microsoft 365, security gateway, Google, Yahoo, Zoho, Amazon, Apple, Fastmail, Proton, and other. Promotion gates include:
  • one latest decision-grade label per unique address, so repeated sends to the same recipient cannot inflate sample size or statistical confidence;
  • observed hard-bounce rate for valid and valid_role_based decisions;
  • the Wilson 95% upper confidence bound;
  • Wilson bounds for delivery recall and false-invalid risk;
  • a minimum of 300 decision-grade outcomes per Microsoft segment;
  • at least 50% send-decision coverage across decision-grade segment outcomes;
  • at least 90% delivery send recall, so an overly cautious policy cannot win by hiding deliverable mail behind risky, unknown, or invalid;
  • no more than 1% delivered-after-invalid outcomes;
  • separate operational and statistically supported sub-1% claim states;
  • an overall gate plus gates for each bounded provider segment;
  • provider-breadth readiness requiring at least four named provider families, each with at least 20 decision-grade outcomes; and
  • delivered-after-invalid and hard-bounce-after-send-recommended counters.
A passing observed rate does not automatically authorize a public accuracy claim. Both promotion states require coverage, delivery-recall, and false-invalid gates to pass; use sub_one_percent_claim_ready for the stricter state that also requires the hard-bounce and false-invalid upper bounds plus the delivery-recall lower bound to meet their targets. Use report.readiness.operational_rollout_ready as the fail-closed rollout signal. It requires the overall operational gate, the combined Microsoft gate, and provider breadth to pass. Use report.readiness.sub_one_percent_claim_ready as the statistical claim result: the overall and combined Microsoft confidence gates must pass, and at least four provider families must independently be claim-grade. A large cohort from only Microsoft cannot satisfy either breadth requirement. The strongest first-party prospective signal is evidence_readiness.market_claim_ready, which additionally requires representative prospective send coverage, including a passing Microsoft-only prospective gate. Despite its compatibility name, that field does not evaluate another validator. Comparative market-leadership language also requires a verified competitive benchmark v9 report for GTMAPIs and at least two named competitors, with every loss and abstention published. It must pass its domain-diversity input gate and publish both subject-level paired tests and equal-domain-weight exact sign tests.