EviMail is the Namirial Notify service for sending certified emails. The recipient gets a normal email in their inbox, and Namirial Notify records evidence for each phase of the delivery so you can prove that the message was sent, delivered, and — when configured — opened, accepted, or rejected.
This page is the integration guide. For the REST contract, see the EviMail API reference. For shared concepts and terminology used across services, see States and outcomes and Evidence and affidavits.
Pick EviMail when the certified content is the email message itself and your integration needs to prove that the message reached the recipient's mailbox. Pick a different service when:
- You need recipients to access content inside a hosted notice and record their on-platform actions. Use EviNotice.
- You need to deliver to a phone via SMS or RCS. Use EviSMS.
- You need an electronic signature workflow on a document. Use EviSign.
- You need certified physical mail. Use EviPost.
A side-by-side comparison is on the Services page.
EviMail involves a small set of related concepts. Keep these distinct as you read the rest of the page.
- Communication — a single submission to
POST /v1/EviMail/Submit. Identified byeviId(returned in the response) and, optionally, by your ownLookupKey. - Recipient — one main recipient (
Recipient.EmailAddress) and optionalCarbonCopy[]addresses. Only the main recipient generates evidence events. - Event — a recorded fact during the lifecycle, such as
SentorDelivered. Some events also drive state transitions. - State — the current phase of the communication. See the state table below.
- Evidence item — the recorded data behind an event. The Query endpoint exposes evidence summaries; affidavits certify selected items.
- Affidavit — a signed PDF that certifies one or more evidence items. The
AffidavitKindsyou choose at submit time control which affidavits are generated. - Callback — an HTTP POST that Namirial Notify sends to your
PushNotificationUrlwhen an event matches thePushNotificationFilteryou configured.
The diagram below shows the happy path. The state names match the values returned by the API (see API reference).
Read and Replied are optional and only appear when configured (open tracking enabled, and CommitmentOptions enabled for accept/reject). Closed is terminal.
For a state model that includes the failure path, see:
Failed is not necessarily terminal. The platform may retry. Wait for Closed (with a final Outcome) before declaring the communication a permanent failure.
The diagram below combines the happy-path sequence with the callbacks and affidavits that fire at each step. Use it as a quick reference for what to expect at any given state.
CB = callback delivered to PushNotificationUrl (if that kind is in PushNotificationFilter). AFF = affidavit generated (if that kind is in AffidavitKinds). Both are opt-in — configure them at submit time or neither fires.
Only three fields are required: Subject, Body, and Recipient.EmailAddress. Everything else is optional but operationally important.
Minimal valid request
curl -X POST "https://api.evicertia.com/v1/EviMail/Submit" \
-u "$EVI_USER:$EVI_PASS" \
-H "Content-Type: application/json" \
-H "X-Evi-IdempotencyToken: 3f1a8b40-1f4a-4c2c-8f3a-cabf12a14b6c" \
-d '{
"Subject": "Your certified policy update",
"Body": "<p>Hello, please review the attached document.</p>",
"Recipient": {
"EmailAddress": "recipient@example.com"
}
}'This is enough to get a certified email delivered and tracked. The platform uses account defaults for certification level, language, and all other settings. No callbacks, no affidavits beyond the defaults — useful for a first smoke-test.
Beyond the three required fields, every other field — including everything in Options — is optional at the API level. When you omit one, the platform applies an account or site default (for example Language follows your site's configured language). The web submission form pre-selects these defaults, which is why they can look mandatory in the portal — but the API only requires Subject, Body, and Recipient.EmailAddress.
Full production request
curl -X POST "https://api.evicertia.com/v1/EviMail/Submit" \
-u "$EVI_USER:$EVI_PASS" \
-H "Content-Type: application/json" \
-H "X-Evi-IdempotencyToken: 3f1a8b40-1f4a-4c2c-8f3a-cabf12a14b6c" \
--data @evimail-submit.jsonevimail-submit.json:
{
"Subject": "Your certified policy update",
"Body": "<p>Hello, please review the attached document.</p>",
"LookupKey": "ORDER-12345",
"IssuerName": "Sender Corp.",
"From": "sender@example.com",
"ReplyTo": "reply@example.com",
"Recipient": {
"LegalName": "Acme Corp",
"EmailAddress": "recipient@example.com"
},
"CarbonCopy": [
{ "Name": "QA Team", "EmailAddress": "qa@example.com" }
],
"Attachments": [
{
"DisplayName": "Policy",
"Filename": "policy.pdf",
"MimeType": "application/pdf",
"Data": "JVBERi0xLjQgZXhhbXBsZQ==",
"Attributes": [
{ "Key": "IncludeOnAffidavits", "Value": "true" }
]
}
],
"Options": {
"CertificationLevel": "Advanced_EU",
"TimeToLive": 1440,
"Language": "en",
"AffidavitLanguage": "en",
"AffidavitKinds": ["Submitted", "DeliveryResult", "Read", "Closed"],
"PushNotificationUrl": "https://your-system.example.com/callbacks/evimail",
"PushNotificationFilter": ["Sent", "Delivered", "Read", "Failed", "Closed"],
"PushNotificationExtraData": "order-12345",
"EvidenceAccessControlMethod": "Public",
"OnlineRetentionPeriod": 1
}
}On success the response is:
{
"eviId": "87ffa214e7734bd59b8da8ef00fd80f8"
}Persist both eviId and your LookupKey. You need them to reconcile against Query results and to correlate incoming callbacks.
LookupKey— string. Your correlation key for this communication. Passed back verbatim in every callback (AdditionalData.LookupKey) and filterable in Query viaWithLookupKeys. The platform does not enforce uniqueness — two submissions with the sameLookupKeyare both accepted — so enforce uniqueness within your domain. Avoid characters that require URL encoding (spaces,&,#, etc.) if you intend to useWithLookupKeysas a query parameter. Omitting this field makes reconciliation significantly harder.IssuerName— string. The legal entity name declared as the sender of the certified communication. This value appears on the generated affidavit PDFs and on the Namirial Notify hosted evidence page. It is not the same asFrom—IssuerNameis the legal record of who initiated the communication, whileFromis the inbox sender address the recipient sees. Use the full registered legal name of the sending organization.From— email address string. The sender address displayed in the recipient's inbox. Your account is pre-configured with a set of permitted sender addresses. The most common error cases: a malformed or unregistered address returns400 Bad Request; using the account's own reserved default From address returns403 Forbidden. Confirm the permitted addresses with your Namirial Notify contact before going live — this is a common source of integration failures in pre-production.ReplyTo— email address string. Sets the reply-to header on the delivered email. Affects only how the recipient's mail client handles a reply action; it plays no role in the evidence chain or certification. Omit it if recipients should not be able to reply.Options.CertificationLevel— enum string. The legal framework and regional variant applied to this communication. Supported values includeStandard,Advanced, and country-specific variants such asStandard_EU,Advanced_EU,Standard_CO, orAdvanced_MX. The set available to your account depends on your subscription — submitting an unsupported level returns400 Bad Requestwith a field-level error. Confirm available levels with your Namirial Notify contact.Options.TimeToLive— integer, minutes. How long the platform tracks the communication before closing its lifecycle. When the TTL elapses, the final outcome is derived from the milestones recorded up to that point, such asCertified,Sent,Delivered,Read, orFailed. TTL expiry does not itself mean failure; the outcome isFailedonly when a failure was recorded. If omitted, the account's default TTL is used.Options.AffidavitKinds— array of enum strings. The affidavit types you want generated for this communication. Generation is asynchronous and fires at the lifecycle moment each type is tied to (see the affidavit table). An invalid or unsupported value returns400. Choosing more kinds than you need increases storage and callback volume. See Evidence and affidavits for the full catalog and legal implications of each type.Options.PushNotificationUrl— URL string. Your HTTPS endpoint to receive callbacks. Usinghttp://instead ofhttps://reduces the callback payload:AdditionalData.XmissionDetails(onSentcallbacks) andAdditionalData.Comments(onRepliedcallbacks) are stripped from HTTP responses. The URL must be publicly reachable from the Namirial Notify infrastructure — localhost, private network, or VPN-only addresses will silently exhaust retries. See Callbacks and what you receive for the full delivery contract.Options.PushNotificationFilter— array of enum strings. The callback kinds you want delivered. Valid values:Ready,Dispatched,Sent,Delivered,Read,Replied,Failed,Closed,AffidavitPublished. Submitting an invalid or duplicate value returns400 Bad Request. An empty array disables all callbacks. Subscribe only to the kinds you act on — each extra subscription multiplies retry traffic when your endpoint is unhealthy.Options.PushNotificationExtraData— string. An arbitrary value set at submit time that is echoed verbatim inAdditionalData.ExtraDataon every callback for this communication. Use it to embed a routing key, tenant identifier, or your internal record ID so your callback handler can process the event without a separate lookup. Any string value is accepted; there is no structural format requirement.Options.CommitmentOptions— enum string. Enables and configures the accept/reject interaction for the recipient. Without this field (or withDisabled), the recipient never reachesRepliedstate. Cannot be changed after submission. See Accept/reject commitment below for the full behavior and related fields.Options.EvidenceAccessControlMethod— enum string. Controls how the recipient authenticates before accessing the Namirial Notify hosted evidence page. Behavior per value:Public— no authentication required; anyone with the link can view the evidence page. Simplest recipient experience.Challenge— sends the recipient a one-time authentication code via a secondary channel before granting access.AutoChallenge— automatically selects the appropriate challenge method based on the recipient's registered profile.
Use
Publicfor lowest friction; useChallengeorAutoChallengefor communications that contain sensitive content or require stronger access control.Options.OnlineRetentionPeriod— integer, years. How long the communication record — evidence items, affidavits, and the hosted evidence page — remains accessible online through the Namirial Notify platform. After this period, the record may be archived or removed from online access. Note: this does not affect the legal validity of affidavit PDFs you have already downloaded — those are self-contained signed documents. Valid values depend on your account subscription; confirm with your Namirial Notify contact.Options.Language— enum string. The language for the notification email sent to the recipient. Accepted values:ca,de,en,es,fr,it,pt,pt-BR,ro. Defaults to the account's configured language when omitted. This controls recipient-facing UI text, not the content of yourBodyfield.Options.AffidavitLanguage— enum string. The language of generated affidavit PDFs. Accepted values:ca,de,en,es,fr,it,pt,pt-BR,ro,el. Noteel(Greek) is available for affidavits but not forLanguage. Defaults to the account's configured affidavit language when omitted.
Include the X-Evi-IdempotencyToken header on every Submit. Use a UUID and keep it across retries.
- A replay that matches a cached
200 OKreturns202 Acceptedwith the original body. - A replay that arrives while the first request is still in flight returns
409 Conflict. Back off briefly and resend the same token. - Responses
400,401,408,409,429, and5xxare not cached; the next request with the same token is re-executed.
The response also carries an X-Evi-IdempotencyStatus header with one of New, Replay, or Conflict, so your client can branch deterministically without parsing the body.
Options.CommitmentOptions controls whether and how the recipient can accept or reject the certified communication. It accepts one of four values:
| Value | Effect |
|---|---|
Disabled | No commitment interaction. The recipient receives the email as normal. This is commonly disabled unless platform configuration sets another default. |
Accept | The recipient is shown an Accept button on the Namirial Notify hosted page. |
Reject | The recipient is shown a Reject button. |
AcceptOrReject | The recipient can choose to Accept or Reject. |
When commitment is enabled, the email body includes a link to a hosted Namirial Notify page where the recipient takes the configured action. Their response transitions the communication to Replied state with outcome Accepted or Rejected.
Related fields you can combine with CommitmentOptions:
Options.CommitmentCommentsAllowed(true/false) — whentrue, the recipient can enter a free-text comment alongside their response. The comment is included in theRepliedcallback'sAdditionalData.Commentsfield (HTTPS endpoints only).Options.RequireAcceptReasonandOptions.AcceptReasons— whenRequireAcceptReasonistrue, the recipient must pick a reason from theAcceptReasonslist before accepting.Options.RequireRejectReasonandOptions.RejectReasons— same pattern for rejection.
Accept/reject reason fields require CommitmentCommentsAllowed: true. Accept-only reason fields are not valid with CommitmentOptions: Reject, and reject-only reason fields are not valid with CommitmentOptions: Accept.
When the recipient completes the action, the Replied callback fires with AdditionalData.Kind identifying whether the action was an acceptance or rejection. The Committed or CommittedAdvanced affidavit is generated at this point (if included in AffidavitKinds).
CommitmentOptions cannot be changed after submission. If your use case requires acceptance or rejection, enable it at submit time.
The recipient receives a normal email in their inbox. The email may include a banner or header indicating it is a certified communication (controlled by Options.DeliveryAppearance).
No action is required from the recipient. Namirial Notify records delivery evidence and, when open tracking is available and configured, records the open as a Read event.
When Options.CommitmentOptions is set to Accept, Reject, or AcceptOrReject, the email includes a link to a Namirial Notify hosted confirmation page. The recipient:
- Receives the email in their inbox.
- Clicks the link in the email to open the hosted page.
- Reviews the content and selects the configured action (accept, reject, or both).
- Optionally adds a comment (if
CommitmentCommentsAllowedistrue). - Submits. The platform records the response and moves the communication to
Replied.
The recipient's response is what generates the Replied callback and the Committed affidavit. If the recipient never clicks the link, the communication eventually reaches Closed without a Replied state.
The hosted confirmation page is served and branded by Namirial Notify. The EvidenceAccessControlMethod you set at submit time controls how recipients authenticate before they can access the page.
Namirial Notify pushes JSON over HTTP to your PushNotificationUrl whenever a state change matches the configured PushNotificationFilter. Callbacks are per-communication and opt-in.
Every callback shares the same envelope:
{
"Identifier": "1234",
"Kind": "Sent",
"Date": "2026-01-22T12:46:32.4830752+01:00",
"EvidenceId": "2aca3ea149f943879726a87000c1f704",
"EvidenceType": "eviMail",
"Site": "my-site",
"Owner": null,
"OwnerEmail": "sender@example.com",
"AdditionalData": {
"From": "sender@example.com",
"To": "recipient@example.com",
"Subject": "Your certified policy update",
"LookupKey": "ORDER-12345",
"State": "Sent",
"CreationDate": "2026-01-22T12:46:12.3113880+01:00",
"XmissionDetails": "Successfully sent to recipient's mail server.",
"ExtraData": "order-12345"
}
}Use Identifier as the idempotency key on your side. The shared Callbacks and webhooks page documents the full payload structure, retry behavior, and per-service field tables.
HTTPS unlocks extra detail. The XmissionDetails field on Sent callbacks and the Comments field on Replied callbacks are only included when PushNotificationUrl uses HTTPS.
Namirial Notify sends callbacks as plain HTTP POST requests with no authentication header — there is nothing in the request itself that proves it came from the platform. Apply layered defenses on your endpoint:
Use HTTPS. Required for the full payload and for any endpoint handling certified evidence data. HTTP endpoints are accepted by the API but should only be used during local development.
Restrict by IP. Allowlist only the egress IP ranges used by the Namirial Notify callback infrastructure at your network or load-balancer layer. Requests from any other source are dropped before they reach your application. Obtain the current IP range list from your Namirial Notify contact — ranges can change, so subscribe to update notifications if your contact provides them.
Validate the payload before acting on it. On every incoming callback, check:
EvidenceTypeequals"eviMail"— reject anything else silently.EvidenceIdmatches a communication you submitted — cross-reference against your own records and discard unknown IDs.Kindis one of the values you subscribed to inPushNotificationFilter— anything outside that set is unexpected.
Log and discard any callback that fails these checks. Do not update business state based on a callback you cannot corroborate.
Keep the URL low-profile. Treat PushNotificationUrl as a secret: do not publish it in client-side code, documentation, or unredacted logs. If you suspect it has been exposed, set a new URL on future submissions — the URL is fixed at submit time and cannot be changed for in-flight communications, so rotate promptly and monitor existing open communications until they close.
Respond quickly with a 2xx. Return the status code before doing any heavy processing, and handle the work in a background queue. A slow response risks a timeout-triggered retry, which multiplies traffic on your endpoint and may create duplicate processing if your handler is not idempotent.
Delivered — delivery confirmation received
{
"Identifier": "2345",
"Kind": "Delivered",
"Date": "2026-01-22T12:47:05.0000000+01:00",
"EvidenceId": "87ffa214e7734bd59b8da8ef00fd80f8",
"EvidenceType": "eviMail",
"Site": "my-site",
"Owner": null,
"OwnerEmail": "sender@example.com",
"AdditionalData": {
"From": "sender@example.com",
"To": "recipient@example.com",
"Subject": "Your certified policy update",
"LookupKey": "ORDER-12345",
"State": "Delivered",
"CreationDate": "2026-01-22T12:46:12.3113880+01:00",
"Progress": "Confirmation of message delivery",
"Description": "The message or the notification with the link were delivered to the final recipient, but the content still has not been opened/read.",
"ExtraData": "order-12345"
}
}The Delivered state or callback confirms a delivery milestone but does not close the lifecycle. Wait for Closed, then inspect Outcome for the final result. If requested, the DeliveryResult affidavit records the delivery result; use DeliveredOn and the event details, not the affidavit kind alone, to confirm success.
Read — recipient opened the message (open tracking enabled)
{
"Identifier": "3456",
"Kind": "Read",
"Date": "2026-01-22T13:15:42.0000000+01:00",
"EvidenceId": "87ffa214e7734bd59b8da8ef00fd80f8",
"EvidenceType": "eviMail",
"Site": "my-site",
"Owner": null,
"OwnerEmail": "sender@example.com",
"AdditionalData": {
"From": "sender@example.com",
"To": "recipient@example.com",
"Subject": "Your certified policy update",
"LookupKey": "ORDER-12345",
"State": "Read",
"CreationDate": "2026-01-22T12:46:12.3113880+01:00",
"Progress": "Notification of opening or reading of the message",
"Description": "The message has been opened or read by the final recipient.",
"ExtraData": "order-12345"
}
}Open tracking is best-effort. Deduplicate on Identifier — the same open event can fire more than once if the recipient opens the message multiple times. The Read affidavit is generated only once.
Failed — delivery attempt failed
{
"Identifier": "4567",
"Kind": "Failed",
"Date": "2026-01-22T12:51:00.0000000+01:00",
"EvidenceId": "c3d4e5f601234bd59b8da8ef00fd80f8",
"EvidenceType": "eviMail",
"Site": "my-site",
"Owner": null,
"OwnerEmail": "sender@example.com",
"AdditionalData": {
"From": "sender@example.com",
"To": "recipient@example.com",
"Subject": "Your certified policy update",
"LookupKey": "ORDER-99999",
"State": "Failed",
"CreationDate": "2026-01-22T12:46:12.3113880+01:00",
"Progress": "There was an error that precludes normal processing of the message.",
"Description": "An unrecoverable error occurred or the retry limit has been reached, making it impossible to send the message.",
"ExtraData": "order-99999"
}
}Failed is not terminal on its own — the platform may retry. Do not resubmit. Wait for the Closed callback and check AdditionalData.Outcome. Permanent failure is Closed with Outcome: Failed.
Replied — recipient accepted (HTTPS endpoint, CommitmentOptions enabled)
{
"Identifier": "5678",
"Kind": "Replied",
"Date": "2026-01-22T14:23:10.0000000+01:00",
"EvidenceId": "87ffa214e7734bd59b8da8ef00fd80f8",
"EvidenceType": "eviMail",
"Site": "my-site",
"Owner": null,
"OwnerEmail": "sender@example.com",
"AdditionalData": {
"From": "sender@example.com",
"To": "recipient@example.com",
"Subject": "Your certified policy update",
"LookupKey": "ORDER-12345",
"State": "Replied",
"CreationDate": "2026-01-22T12:46:12.3113880+01:00",
"Kind": "Accepted",
"Comments": "I agree with the terms and conditions.",
"ExtraData": "order-12345"
}
}AdditionalData.Kind is Accepted or Rejected — branch on this to determine the recipient's commitment decision. Comments is only present when PushNotificationUrl uses HTTPS and CommitmentCommentsAllowed was true.
Closed — lifecycle ended, outcome assigned
{
"Identifier": "9012",
"Kind": "Closed",
"Date": "2026-01-22T14:25:00.0000000+01:00",
"EvidenceId": "87ffa214e7734bd59b8da8ef00fd80f8",
"EvidenceType": "eviMail",
"Site": "my-site",
"Owner": null,
"OwnerEmail": "sender@example.com",
"AdditionalData": {
"From": "sender@example.com",
"To": "recipient@example.com",
"Subject": "Your certified policy update",
"LookupKey": "ORDER-12345",
"State": "Closed",
"CreationDate": "2026-01-22T12:46:12.3113880+01:00",
"Outcome": "Accepted",
"OutcomeDescription": "The communication was accepted by the recipient.",
"ExtraData": "order-12345"
}
}Closed is the terminal event. AdditionalData.Outcome holds the final result — Delivered, Accepted, Rejected, Failed, etc. Always wait for Closed before marking a transaction complete on your side.
AffidavitPublished — an affidavit has been generated and is ready to download
{
"Identifier": "6789",
"Kind": "AffidavitPublished",
"Date": "2026-01-22T12:48:30.0000000+01:00",
"EvidenceId": "87ffa214e7734bd59b8da8ef00fd80f8",
"EvidenceType": "eviMail",
"Site": "my-site",
"Owner": null,
"OwnerEmail": "sender@example.com",
"AdditionalData": {
"From": "sender@example.com",
"To": "recipient@example.com",
"Subject": "Your certified policy update",
"LookupKey": "ORDER-12345",
"State": "Delivered",
"CreationDate": "2026-01-22T12:46:12.3113880+01:00",
"AffidavitId": "a1b2c3d4e5f641239726a87000c1f704",
"AffidavitKind": "DeliveryResult",
"AffidavitName": "Certification of delivery",
"ExtraData": "order-12345"
}
}One AffidavitPublished callback fires per generated affidavit. Persist AdditionalData.AffidavitId — it is the key for downloading the PDF from the API. AdditionalData.AffidavitKind tells you which lifecycle moment the affidavit covers (see the affidavit table). For on-demand affidavits requested via POST /v1/EviMail/AffidavitRequest, the callback also includes AdditionalData.RequestId so you can correlate it with your original request. If the affidavit was regenerated, AdditionalData.Regenerated is true.
Kind | When it fires | Final business outcome? | Affidavit-bearing? | Extra fields in AdditionalData | What you should do |
|---|---|---|---|---|---|
Ready | After admission and content certification | No | Indirect (Submitted / SubmittedAdvanced) | — | Optional internal "queued" → "processed" transition |
Dispatched | After sending is requested and the message is ready for the sender component | No | — | Progress, Description | Update tracking |
Sent | After the recipient's mail server accepts the message | No | TransmissionResult | XmissionDetails (HTTPS only) | Update tracking; do not retry on your side |
Delivered | After delivery confirmation is received | No | DeliveryResult | Progress, Description | Treat as confirmed delivery |
Read | After open is detected | No | Read | Progress, Description | Open tracking is best-effort. Deduplicate on Identifier |
Replied | After the recipient accepts or rejects (when CommitmentOptions enabled) | No (the decision is recorded, but the lifecycle may remain open) | Committed / CommittedAdvanced | Kind (accept / reject), Comments (HTTPS only) | Branch on AdditionalData.Kind; persist Comments when present; wait for Closed |
Closed | When tracking ends | Yes | Closed, Complete, Failed | Outcome, OutcomeDescription | Mark the transaction terminal |
Failed | On send or delivery failure | No (terminal failure is signaled by Closed with Outcome: Failed) | Failed (when terminal) | Progress, Description | Do not resubmit; wait for Closed |
AffidavitPublished | Each time an affidavit is published (per-event or on-demand) | No | The affidavit itself | AffidavitId, AffidavitKind, AffidavitName; RequestId if on-demand; Regenerated if true | Download the affidavit by AffidavitId |
All callbacks share a common set of fields. Some fields only appear on specific event types or under specific conditions.
Fields present in every callback
| Field | Type | Description |
|---|---|---|
From | string | Sender address as configured on Submit |
To | string | Main recipient address |
Subject | string | Email subject |
LookupKey | string | Your correlation key (omitted if not set on Submit) |
State | string | Current communication state at the time of the callback |
CreationDate | ISO 8601 | Timestamp when the communication was first submitted |
ExtraData | string | Verbatim copy of PushNotificationExtraData from Submit (omitted if not set) |
Event-specific fields
| Field | Present on | Condition | Description |
|---|---|---|---|
XmissionDetails | Sent | HTTPS endpoint only | Human-readable summary of the SMTP handoff result |
Progress | Dispatched, Delivered, Read, Failed | Always | Human-readable string describing the current processing stage |
Description | Dispatched, Delivered, Read, Failed | Always | Human-readable description of the event outcome |
Kind | Replied | Always | Accepted or Rejected — the recipient's commitment decision |
Comments | Replied | HTTPS endpoint + CommitmentCommentsAllowed: true | Free-text comment entered by the recipient |
Outcome | Closed | Always | Final outcome: Delivered, Accepted, Rejected, Failed, etc. |
OutcomeDescription | Closed | Always | Human-readable description of the final outcome |
AffidavitId | AffidavitPublished | Always | Unique identifier of the generated affidavit — use this to download the PDF |
AffidavitKind | AffidavitPublished | Always | Which affidavit type was generated (e.g. DeliveryResult, Committed) |
AffidavitName | AffidavitPublished | Always | Display name of the affidavit document |
RequestId | AffidavitPublished | On-demand affidavits only | Correlates the callback to the original AffidavitRequest call |
Regenerated | AffidavitPublished | Only when true | Present and true when this affidavit replaced a previously generated one |
The Query endpoint and callbacks both expose the State value. Use this table to interpret it.
| Display name | Technical name | When it occurs | Final? | Callback repeatable? | Related callback | Affidavit implication | What you should do |
|---|---|---|---|---|---|---|---|
| Draft | Draft | Saved in UI but not submitted | No | No | — | — | Not visible via API |
| New | New | Submit accepted; admission and content certification begin | No | No | — | Submitted / SubmittedAdvanced once certified | Store eviId and LookupKey for reconciliation |
| Ready | Ready | Validated, certified, and ready for sending | No | No | Ready | — | Optional UI transition |
| Dispatched | Dispatched | Sending has been requested; the message is ready for the sender component | No | No | Dispatched | — | Update tracking; not yet sent or delivered |
| Sent | Sent | Recipient's mail server accepted the message | No | No | Sent | TransmissionResult | Reconcile against your in-flight set |
| Delivered | Delivered | Delivery confirmation was received | No | No | Delivered | DeliveryResult | Surface "delivered" to the operator |
| Read | Read | Recipient opened the message (when supported) | No | Yes — fires on each open; deduplicate on Identifier | Read | Read (generated once regardless) | Treat as best-effort; deduplicate on Identifier |
| Replied | Replied | Recipient accepted or rejected (when configured) | No | No | Replied | Committed / CommittedAdvanced | Branch on Kind from the callback |
| Closed | Closed | Tracking ended; outcome assigned | Yes | No | Closed | Closed / ClosedAdvanced, often Complete / CompleteAdvanced | Mark the transaction terminal |
| Failed | Failed | Delivery failure occurred; retries may still follow | No | Yes — fires on each retry attempt | Failed | Failed (when terminal) | Wait for Closed before declaring permanent failure |
Unknown is enum padding for forward compatibility; treat it as "unmapped" and rely on the recorded timestamps.
For outcomes (None, Certified, Sent, Delivered, Read, Accepted, Rejected, Failed), see the API reference.
EviMail records evidence for relevant lifecycle and technical events, and the AffidavitKinds you set at submit time control which of those items get certified into signed PDF affidavits. The full catalog and formal definitions are in Evidence and affidavits.
The table below maps the AffidavitKinds values to the lifecycle moment that triggers generation. All values are optional and configured at submit time except OnDemand, which is triggered on request.
AffidavitKinds value | Triggered at | Notes | AffidavitPublished callback fires? |
|---|---|---|---|
Submitted | New → Ready (content certified) | Certifies admission, content, and metadata | Yes, if in PushNotificationFilter |
SubmittedAdvanced | New → Ready | Advanced variant; includes rendered body | Yes |
TransmissionResult | Sent (SMTP response received) | Certifies the handoff to the recipient mail server | Yes |
DeliveryResult | Delivered (delivery confirmation/result received) | Certifies the delivery result | Yes |
Read | Read (recipient opened the message) | Only generated once, even if open is detected multiple times | Yes |
Committed | Replied (recipient accepted or rejected) | Certifies the acceptance or rejection action | Yes |
CommittedAdvanced | Replied | Advanced variant of the commitment affidavit | Yes |
Closed | Closed | Certifies the end of tracking | Yes |
ClosedAdvanced | Closed | Advanced variant | Yes |
Complete | Closed | Certifies the full chain from submission to closure, regardless of final result | Yes |
CompleteAdvanced | Closed | Advanced variant of the complete lifecycle affidavit, regardless of final result | Yes |
OnDemand | On request via POST /v1/EviMail/AffidavitRequest | Requires OnDemand in AffidavitKinds at submit time and an eligible, non-closed communication | Yes, with RequestId in AdditionalData |
Event | Technical events when generated by the configured affidavit kinds | Internal technical record for events that do not have a more specific affidavit kind | Yes |
Failed | Closed following terminal failure | Only when the final outcome is failure | Yes |
Key things to know:
- Every generated affidavit fires an
AffidavitPublishedcallback to the originalPushNotificationUrl, but only ifAffidavitPublishedis inPushNotificationFilter. The callback includesAffidavitId,AffidavitKind, andAffidavitNameinAdditionalData. - Affidavit generation is asynchronous. The affidavit is not available instantly after the state transition — wait for the
AffidavitPublishedcallback or poll withIncludeAffidavits=trueon Query. - To enable on-demand affidavits, include
OnDemandinAffidavitKindsat submit time. This cannot be enabled retroactively. - On-demand affidavit requests are rejected when the communication is
Draft, alreadyClosed, not enabled for on-demand affidavits, over the configured maximum request count, or requested by a non-owner. - You can also retrieve affidavit metadata via the Query endpoint without subscribing to callbacks.
If OnDemand was included in AffidavitKinds at submit time and the communication is still eligible, you can request an additional affidavit later with POST /v1/EviMail/AffidavitRequest (see the API reference). The generation is asynchronous; you receive an AffidavitPublished callback when it is ready.
Use the Query endpoint as a fallback when callbacks lag, when you need a point-in-time snapshot, or for batch reconciliation. The most common filters:
WithUniqueIds=<eviId>— fetch one or more communications by id.WithLookupKeys=<your-key>— fetch by your correlation key.OnState=Closed— fetch only closed communications.WithOutcome=Delivered— fetch by final outcome.IncludeAffidavits=true— include affidavit metadata in results.
Example:
curl -X GET "https://api.evicertia.com/v1/EviMail/Query?WithLookupKeys=ORDER-12345&IncludeAffidavits=true" \
-u "$EVI_USER:$EVI_PASS"Response:
{
"totalMatches": 1,
"results": [
{
"uniqueId": "87ffa214e7734bd59b8da8ef00fd80f8",
"lookupKey": "ORDER-12345",
"state": "Closed",
"outcome": "Delivered",
"creationDate": "2026-01-22T12:46:12.3113880Z",
"sentOn": "2026-01-22T12:46:32.4830752Z",
"deliveredOn": "2026-01-22T12:47:05.1023400Z",
"affidavits": [
{ "uniqueId": "…", "kind": "Submitted", "name": "Certification of admission" },
{ "uniqueId": "…", "kind": "DeliveryResult", "name": "Certification of delivery" },
{ "uniqueId": "…", "kind": "Closed", "name": "Certification of closure" }
]
}
]
}For the full filter and response schema, see the API reference.
Run through these steps before wiring EviMail into production. The goal is to confirm that the full round-trip — submit, receive callbacks, verify state, and download an affidavit — works end-to-end from your system.
- API credentials —
EVI_USERandEVI_PASSfor your account. Obtain them from your Namirial Notify contact. Keep them out of source control. - A recipient address you control — use a personal or team inbox so you can observe what the recipient receives and verify delivery.
- An HTTPS endpoint for callbacks (optional for the smoke-test, required to receive
XmissionDetailsandComments) — the URL must be reachable from the public internet. If you do not have one yet, use a webhook inspection tool or a local tunnel to expose a port on your machine temporarily.
Submit a minimal request using a recipient address you control. Generate a fresh UUID for the idempotency token each time you submit a new communication.
curl -X POST "https://api.evicertia.com/v1/EviMail/Submit" \
-u "$EVI_USER:$EVI_PASS" \
-H "Content-Type: application/json" \
-H "X-Evi-IdempotencyToken: 3f1a8b40-1f4a-4c2c-8f3a-cabf12a14b6c" \
-d '{
"Subject": "Test certified email",
"Body": "<p>This is a test from EviMail integration.</p>",
"LookupKey": "TEST-001",
"Recipient": {
"EmailAddress": "your-inbox@example.com"
},
"Options": {
"AffidavitKinds": ["Complete"],
"PushNotificationUrl": "https://your-endpoint.example.com/callbacks/evimail",
"PushNotificationFilter": ["Sent", "Delivered", "Closed", "AffidavitPublished"]
}
}'Expected response:
{ "eviId": "87ffa214e7734bd59b8da8ef00fd80f8" }Save eviId. If you get 400, check responseStatus.errors[] for the failing field. If you get 401 or 403, confirm credentials and that your account is provisioned for EviMail.
Query the communication a few seconds after submitting to confirm it has moved out of New:
curl "https://api.evicertia.com/v1/EviMail/Query?WithLookupKeys=TEST-001" \
-u "$EVI_USER:$EVI_PASS"You should see "state": "Dispatched" or "state": "Sent" within seconds. If still "state": "New", wait and retry — the platform is still processing admission. If it stays in New for more than a minute, contact support.
If you configured a PushNotificationUrl, check your endpoint logs as the communication progresses. You should receive Kind: Sent and eventually Kind: Closed. If the delivery infrastructure reports a delivery signal, you also receive Kind: Delivered. Because callbacks are independent messages and can arrive out of order, use their timestamps and query the transaction before making irreversible decisions.
If you did not configure a callback URL, poll Query every 10–30 seconds until "state": "Closed":
curl "https://api.evicertia.com/v1/EviMail/Query?WithLookupKeys=TEST-001" \
-u "$EVI_USER:$EVI_PASS"When Closed, check "outcome". If delivery confirmation was received, the expected outcome is "Delivered"; otherwise, "Sent" can be final even if the email arrived. Also check "deliveredOn" and your inbox.
Because you included Complete in AffidavitKinds, an AffidavitPublished callback fires when the affidavit is ready. Query with IncludeAffidavits=true to get the affidavit metadata:
curl "https://api.evicertia.com/v1/EviMail/Query?WithLookupKeys=TEST-001&IncludeAffidavits=true" \
-u "$EVI_USER:$EVI_PASS"Look for affidavits[] in the response. Use the uniqueId of the Complete affidavit to download the PDF via the Affidavit endpoint (see the API reference). Open it and confirm it is signed and shows the recorded lifecycle timestamps. A delivery timestamp is present only when delivery confirmation was recorded.
Resubmit using an address that will fail delivery — confirm this address with your Namirial Notify contact. Verify that:
- The communication eventually reaches
"state": "Closed"with"outcome": "Failed". - You receive both
Kind: FailedandKind: Closedcallbacks. They can be retried or arrive out of order, so reconcile them with Query. - Your system handles
Outcome: Failedwithout triggering an automatic resubmit.
This exercises your error-handling code before any real communications go through.
- Set
LookupKeyon every Submit and persisteviIdfrom the response. - Send
X-Evi-IdempotencyToken(UUIDv4) on every Submit. Treat202 Acceptedas success and409 Conflictas "retry with the same token after a short backoff". - Use HTTPS for
PushNotificationUrlso you receiveXmissionDetailsandComments. - Subscribe only to the callback kinds you act on. Each extra subscription multiplies retry traffic when your endpoint hiccups.
- Make your callback handler idempotent, keyed on
Identifier. The platform retries on non-2xx and on timeouts. - Store the raw callback body before parsing. This is invaluable for audit and for debugging shape drift.
- Use Query as a fallback when callbacks lag. Filter by
LookupKeyand useIncludeAffidavits=truewhen you need affidavit metadata. - Include
OnDemandinAffidavitKindsat submit time if you intend to callAffidavitRequestlater. This cannot be added retroactively. - Persist
AffidavitIdfromAffidavitPublishedcallbacks. Affidavits are the legal artifact you will need during disputes. - Validate
PushNotificationFiltervalues at submit time. Unsupported or repeated values are rejected by the API, so catch typos before submitting. - Test the happy path and the
Failed→Closed(Outcome: Failed) path in pre-production before going live.
| Symptom | Likely causes | What to check | What to do |
|---|---|---|---|
| No callbacks received | PushNotificationUrl missing on Submit; PushNotificationFilter omits the Kind you expect; endpoint returned non-2xx and retries exhausted; firewall blocks Namirial Notify egress | Events via Query; server access logs for the callback Identifier | Confirm filter and URL; make endpoint publicly reachable; use Query polling as fallback |
Message stays in Dispatched or Sent | Sender processing still pending; recipient MTA slow or greylisting; mailbox full | Timestamps in Query response: dispatchedOn, sentOn, deliveredOn | Wait for Closed; do not resubmit |
deliveredOn is missing but readOn is present | deliveredOn depends on a DSN from the recipient's mail server, which many servers never send; readOn is recorded independently from supported open or read signals | Both timestamps in the Query response | This is expected — an open or read was recorded even though no delivery notification arrived. Treat the message as delivered. See Why delivery and read tracking can be incomplete |
| Recipient says they did not get the email | Spam filter; recipient address typo; alias forwarding broke | Delivered callback and deliveredOn timestamp; XmissionDetails on the Sent callback (HTTPS only) | Confirm the address; ask recipient to check spam; if address is wrong, correct and resubmit with a new idempotency token |
| Duplicate callbacks | Endpoint timed out or returned non-2xx; platform retried | Identifier field — duplicates share the same value | Deduplicate on Identifier; make the callback handler idempotent |
| Affidavit not available | Generation is asynchronous; AffidavitPublished has not fired yet; OnDemand was not included in AffidavitKinds at submit (on-demand requests blocked) | Query with IncludeAffidavits=true | Wait for AffidavitPublished callback; for on-demand, if RequestId was returned but no callback arrived, contact support with that RequestId |
Submit → 400 Bad Request | Missing required field (Subject, Body, or Recipient.EmailAddress); invalid or unsupported enum value (e.g. CertificationLevel not on account); attachment too large | responseStatus.errors[] for field-level details | Fix the flagged field; retry with a new idempotency token |
Submit → 401 Unauthorized | Wrong environment base URL; credentials rotated | Authorization header value; confirm target environment | Re-issue credentials through your Namirial Notify contact |
Submit → 403 Forbidden | Account not provisioned for EviMail; From address not permitted; restricted header in request | responseStatus.message | Contact your Namirial Notify account manager |
Submit → 409 Conflict | Another Submit with the same X-Evi-IdempotencyToken is still in flight | — | Back off briefly; retry with the same token; do not generate a new one |
| Callback payload missing expected fields | Subscribed to a different Kind than the one you are reading; field is HTTPS-only and URL is HTTP; mis-routing on Kind | Kind and EvidenceType on the incoming payload | Route on Kind + EvidenceType first; switch PushNotificationUrl to HTTPS to unlock XmissionDetails and Comments; see Callbacks and webhooks for full field tables |