# What does sendgrid.email.processed prove?

> Prove that Twilio SendGrid accepted the message and can deliver it. Version 1.0.0, certification Provisional.

Canonical: https://provely.sh/verify/sendgrid/sendgrid.email.processed  
Last reviewed: 2026-09-05  
Skill version: 0.1.0  
Certification: provisional  

**Prove that Twilio SendGrid accepted the message and can deliver it. The processed event of this message states it. The 202 response does not: it carries no identifier and no promise.**

*Contract identity.*

| Fact | Value |
| --- | --- |
| Contract id | `sendgrid.email.processed` |
| Version | `1.0.0` |
| Hash | `e062c2cc31e5e1bd` |
| Completion level | `processed` |
| Publisher | Built and signed by Provely. |
| Certification | Provisional |
| Skill | [Twilio SendGrid Mail API 0.1.0](/verify/sendgrid) |
| Valid for provider API versions | `v3` |

## What is the intent?

Hand the message to Twilio SendGrid.

## What is the subject and the action?

| Member | Value |
| --- | --- |
| Subject type | `sendgrid.message` |
| Subject identity | provely_operation_id = `$action.result.provely_operation_id` |
| Canonical effect | `messaging.email_send` |
| Provider operation | `POST /v3/mail/send` |
| Idempotency | none, retry is not safe |

## How does the evidence correlate with this operation?

| Strategy | Assurance | Keys | Required |
| --- | --- | --- | --- |
| `resource_id` | strong | provely_operation_id from `$action.result.provely_operation_id` | yes |
| `fingerprint` | weak | email from `$input.to` | no |

## Which evidence does the contract require?

Minimum evidence level `E3`. An independent channel is required. Minimum channels: 1.

| Channel | Level | Independence | Verifier | Description |
| --- | --- | --- | --- | --- |
| `processed_by_recipient` | E3 | provider event | `webhook` | The processed events for this recipient since the operation started, whatever custom argument they carry. A count above one shows a second message. The verifier returns {events, count, latest, earliest, types, duplicates_dropped}. |
| `processed_events` | E3 | provider event | `webhook` | The processed events that carry the custom argument of this operation. Twilio SendGrid accepted the message and can deliver it. The verifier returns {events, count, latest, earliest, types, duplicates_dropped}. |
| `dropped_events` | E3 | provider event | `webhook` | The dropped events of this operation. Twilio SendGrid dropped the message, and it never reached a receiving server. The verifier returns {events, count, latest, earliest, types, duplicates_dropped}. |

## Which conditions must all hold for VERIFIED?

| Condition | Meaning | Path | Operator | Expected | Evidence |
| --- | --- | --- | --- | --- | --- |
| `processed_event_present` | At least one processed event of this operation arrived. Twilio SendGrid accepted the message and can deliver it. | `$observed.processed_events.count` | `gte` | `1` | `processed_events` |
| `processed_event_present_in_window` | The provider clock of the earliest matched event is after the start of the operation. An older event belongs to another send. | `$observed.processed_events.earliest.provider_timestamp` | `time_after` | `$operation.created_at` | `processed_events` |

## Which conditions give CONTRADICTED?

| Condition | Class | Reason | Path | Operator | Expected |
| --- | --- | --- | --- | --- | --- |
| `wrong_recipient` | wrong subject | The message went to a different recipient than the intent named. | `$observed.processed_events.latest.payload.email` | `ne` | `$input.to` |
| `message_predates_operation` | pre existing state | The earliest event of this message is older than the operation. It proves nothing. | `$observed.processed_events.earliest.provider_timestamp` | `time_before` | `$operation.created_at` |
| `duplicate_message_present` | duplicate side effect | Twilio SendGrid processed more than one message for this recipient since the operation started. Do not retry. | `$observed.processed_by_recipient.count` | `gt` | `1` |

## Which observed states map to a verdict before completion?

| Rule | Match | Verdict | Reason |
| --- | --- | --- | --- |
| `message_dropped` | `$observed.dropped_events.count` gte `1` | FAILED | Twilio SendGrid dropped the message. It never reached a receiving server. |

## How long does the runtime observe?

| Timing member | Value |
| --- | --- |
| Initial delay | 2000 ms |
| Poll interval | 10000 ms |
| Backoff | exponential factor 2, max 300000 ms |
| Maximum attempts | 60 |
| Timeout | 3600000 ms |
| Stale read window | 30000 ms |
| On timeout | UNVERIFIABLE (`evidence_unavailable_before_timeout`), escalated to a person |

## Where do these rules come from?

- `sendgrid.openapi#/paths/~1v3~1mail~1send/post`: [sendgrid.openapi](https://raw.githubusercontent.com/twilio/sendgrid-oai/main/spec/json/tsg_mail_v3.json), retrieved 2026-09-08
- `sendgrid.openapi#/paths/~1v3~1mail~1send/post/responses/202`: [sendgrid.openapi](https://raw.githubusercontent.com/twilio/sendgrid-oai/main/spec/json/tsg_mail_v3.json), retrieved 2026-09-08
- `sendgrid.docs.events#event-webhook/the-processed-event/p1`: [sendgrid.docs.events](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/event), retrieved 2026-09-08
- `sendgrid.docs.mail#the-v3-mail-send-resource/the-response-carries-no-identifier/p1`: [sendgrid.docs.mail](https://www.twilio.com/docs/sendgrid/api-reference/mail-send/mail-send), retrieved 2026-09-08
- `sendgrid.events#/events/processed`: [sendgrid.events](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/event), retrieved 2026-09-08
- `sendgrid.docs.events#event-webhook/custom-arguments/p1`: [sendgrid.docs.events](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/event), retrieved 2026-09-08
- `sendgrid.docs.events#event-webhook/the-event-time/p1`: [sendgrid.docs.events](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/event), retrieved 2026-09-08
- `sendgrid.docs.events#event-webhook/the-properties-of-a-delivery-event/p1`: [sendgrid.docs.events](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/event), retrieved 2026-09-08

### Can sendgrid.email.processed return VERIFIED from the action response alone?

No. The minimum evidence level is E3. The action response is E1. The completion conditions read `processed_events`.

### What happens after the timeout?

The verdict is UNVERIFIABLE with the reason `evidence_unavailable_before_timeout`. The operation goes to a person for review.

## Read next

- [Read the Twilio SendGrid Mail API verification page](https://provely.sh/verify/sendgrid)
- [Read the sendgrid.email.bounced contract](https://provely.sh/verify/sendgrid/sendgrid.email.bounced)
- [Read the sendgrid.email.delivered contract](https://provely.sh/verify/sendgrid/sendgrid.email.delivered)
- [Read what a completion contract contains](https://provely.sh/contracts)
- [Read what a receipt proves](https://provely.sh/docs/receipts)
