Skip to content
Last updated

EviMail

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.


When to use EviMail

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.


How the pieces fit together

EviMail involves a small set of related concepts. Keep these distinct as you read the rest of the page.

via AffidavitPublished
callback or Query

EviMail
communication

Recipient
(1 main + N CC)

Events
(Ready, Dispatched, Sent, Delivered,
Read, Replied, Closed, Failed)

Evidence items
(state transitions + timestamps)

Affidavits
(PDFs signed by Namirial Notify)

Callbacks
(filtered by PushNotificationFilter)

Your system
(HTTPS endpoint)

  • Communication — a single submission to POST /v1/EviMail/Submit. Identified by eviId (returned in the response) and, optionally, by your own LookupKey.
  • Recipient — one main recipient (Recipient.EmailAddress) and optional CarbonCopy[] addresses. Only the main recipient generates evidence events.
  • Event — a recorded fact during the lifecycle, such as Sent or Delivered. 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 AffidavitKinds you choose at submit time control which affidavits are generated.
  • Callback — an HTTP POST that Namirial Notify sends to your PushNotificationUrl when an event matches the PushNotificationFilter you configured.

How EviMail works

The diagram below shows the happy path. The state names match the values returned by the API (see API reference).

optional

optional

optional

POST /v1/EviMail/Submit

State: New
submission accepted

State: Ready
validated + content certified

State: Dispatched
sending requested

State: Sent
accepted by recipient's mail server

State: Delivered
delivery confirmation received

State: Read
recipient opened the message

State: Replied
recipient accepted or rejected

State: Closed
tracking ends, outcome assigned

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:

Submit accepted

content certified

sending requested

accepted by recipient's mail server

send error (may retry)

delivery confirmation

delivery error

recipient opens (when configured)

accepts/rejects without opening (when configured)

accepts/rejects (when configured)

accepts/rejects (when configured)

New

Ready

Dispatched

Sent

Failed

Delivered

Read

Replied

Closed

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.

optional

optional

optional

Submit

New

Ready
CB: Ready
AFF: Submitted

Dispatched
CB: Dispatched

Sent
CB: Sent
AFF: TransmissionResult

Delivered
CB: Delivered
AFF: DeliveryResult

Read
CB: Read
AFF: Read

Replied
CB: Replied
AFF: Committed

Closed
CB: Closed
AFF: Closed · Complete

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.


Submit a certified email

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.json

evimail-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.

Useful fields you should configure

  • LookupKey — string. Your correlation key for this communication. Passed back verbatim in every callback (AdditionalData.LookupKey) and filterable in Query via WithLookupKeys. The platform does not enforce uniqueness — two submissions with the same LookupKey are both accepted — so enforce uniqueness within your domain. Avoid characters that require URL encoding (spaces, &, #, etc.) if you intend to use WithLookupKeys as 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 as FromIssuerName is the legal record of who initiated the communication, while From is 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 returns 400 Bad Request; using the account's own reserved default From address returns 403 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 include Standard, Advanced, and country-specific variants such as Standard_EU, Advanced_EU, Standard_CO, or Advanced_MX. The set available to your account depends on your subscription — submitting an unsupported level returns 400 Bad Request with 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 as Certified, Sent, Delivered, Read, or Failed. TTL expiry does not itself mean failure; the outcome is Failed only 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 returns 400. 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. Using http:// instead of https:// reduces the callback payload: AdditionalData.XmissionDetails (on Sent callbacks) and AdditionalData.Comments (on Replied callbacks) 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 returns 400 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 in AdditionalData.ExtraData on 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 with Disabled), the recipient never reaches Replied state. 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 Public for lowest friction; use Challenge or AutoChallenge for 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 your Body field.

  • Options.AffidavitLanguage — enum string. The language of generated affidavit PDFs. Accepted values: ca, de, en, es, fr, it, pt, pt-BR, ro, el. Note el (Greek) is available for affidavits but not for Language. Defaults to the account's configured affidavit language when omitted.

Idempotency

Include the X-Evi-IdempotencyToken header on every Submit. Use a UUID and keep it across retries.

  • A replay that matches a cached 200 OK returns 202 Accepted with 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, and 5xx are 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.

Accept/reject commitment (CommitmentOptions)

Options.CommitmentOptions controls whether and how the recipient can accept or reject the certified communication. It accepts one of four values:

ValueEffect
DisabledNo commitment interaction. The recipient receives the email as normal. This is commonly disabled unless platform configuration sets another default.
AcceptThe recipient is shown an Accept button on the Namirial Notify hosted page.
RejectThe recipient is shown a Reject button.
AcceptOrRejectThe 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) — when true, the recipient can enter a free-text comment alongside their response. The comment is included in the Replied callback's AdditionalData.Comments field (HTTPS endpoints only).
  • Options.RequireAcceptReason and Options.AcceptReasons — when RequireAcceptReason is true, the recipient must pick a reason from the AcceptReasons list before accepting.
  • Options.RequireRejectReason and Options.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.


What the recipient sees

Standard certified email (no commitment)

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.

Certified email with accept/reject commitment

When Options.CommitmentOptions is set to Accept, Reject, or AcceptOrReject, the email includes a link to a Namirial Notify hosted confirmation page. The recipient:

  1. Receives the email in their inbox.
  2. Clicks the link in the email to open the hosted page.
  3. Reviews the content and selects the configured action (accept, reject, or both).
  4. Optionally adds a comment (if CommitmentCommentsAllowed is true).
  5. 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.


Callbacks and what you receive

Namirial Notify pushes JSON over HTTP to your PushNotificationUrl whenever a state change matches the configured PushNotificationFilter. Callbacks are per-communication and opt-in.

Your callback endpointNamirial NotifyYour callback endpointNamirial Notifystate transition firescallback delivery acknowledgedretry after a configured delayalt[2xx within timeout][error or timeout]filter check (PushNotificationFilter ∋ Kind?)POST PushNotificationUrl (JSON, no auth header)200 OKtimeout or non-2xxPOST again (same Identifier)

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.

Securing your callback endpoint

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:

  • EvidenceType equals "eviMail" — reject anything else silently.
  • EvidenceId matches a communication you submitted — cross-reference against your own records and discard unknown IDs.
  • Kind is one of the values you subscribed to in PushNotificationFilter — 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.

Additional callback payload examples

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.

What each callback means

Kind
When it firesFinal business outcome?Affidavit-bearing?Extra fields in AdditionalDataWhat you should do
ReadyAfter admission and content certificationNoIndirect (Submitted / SubmittedAdvanced)Optional internal "queued" → "processed" transition
DispatchedAfter sending is requested and the message is ready for the sender componentNoProgress, DescriptionUpdate tracking
SentAfter the recipient's mail server accepts the messageNoTransmissionResultXmissionDetails (HTTPS only)Update tracking; do not retry on your side
DeliveredAfter delivery confirmation is receivedNoDeliveryResultProgress, DescriptionTreat as confirmed delivery
ReadAfter open is detectedNoReadProgress, DescriptionOpen tracking is best-effort. Deduplicate on Identifier
RepliedAfter the recipient accepts or rejects (when CommitmentOptions enabled)No (the decision is recorded, but the lifecycle may remain open)Committed / CommittedAdvancedKind (accept / reject), Comments (HTTPS only)Branch on AdditionalData.Kind; persist Comments when present; wait for Closed
ClosedWhen tracking endsYesClosed, Complete, FailedOutcome, OutcomeDescriptionMark the transaction terminal
FailedOn send or delivery failureNo (terminal failure is signaled by Closed with Outcome: Failed)Failed (when terminal)Progress, DescriptionDo not resubmit; wait for Closed
AffidavitPublishedEach time an affidavit is published (per-event or on-demand)NoThe affidavit itselfAffidavitId, AffidavitKind, AffidavitName; RequestId if on-demand; Regenerated if trueDownload the affidavit by AffidavitId

AdditionalData fields by event

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

FieldTypeDescription
FromstringSender address as configured on Submit
TostringMain recipient address
SubjectstringEmail subject
LookupKeystringYour correlation key (omitted if not set on Submit)
StatestringCurrent communication state at the time of the callback
CreationDateISO 8601Timestamp when the communication was first submitted
ExtraDatastringVerbatim copy of PushNotificationExtraData from Submit (omitted if not set)

Event-specific fields

FieldPresent onConditionDescription
XmissionDetailsSentHTTPS endpoint onlyHuman-readable summary of the SMTP handoff result
ProgressDispatched, Delivered, Read, FailedAlwaysHuman-readable string describing the current processing stage
DescriptionDispatched, Delivered, Read, FailedAlwaysHuman-readable description of the event outcome
KindRepliedAlwaysAccepted or Rejected — the recipient's commitment decision
CommentsRepliedHTTPS endpoint + CommitmentCommentsAllowed: trueFree-text comment entered by the recipient
OutcomeClosedAlwaysFinal outcome: Delivered, Accepted, Rejected, Failed, etc.
OutcomeDescriptionClosedAlwaysHuman-readable description of the final outcome
AffidavitIdAffidavitPublishedAlwaysUnique identifier of the generated affidavit — use this to download the PDF
AffidavitKindAffidavitPublishedAlwaysWhich affidavit type was generated (e.g. DeliveryResult, Committed)
AffidavitNameAffidavitPublishedAlwaysDisplay name of the affidavit document
RequestIdAffidavitPublishedOn-demand affidavits onlyCorrelates the callback to the original AffidavitRequest call
RegeneratedAffidavitPublishedOnly when truePresent and true when this affidavit replaced a previously generated one

States reference

The Query endpoint and callbacks both expose the State value. Use this table to interpret it.

Display nameTechnical nameWhen it occursFinal?Callback repeatable?Related callbackAffidavit implicationWhat you should do
DraftDraftSaved in UI but not submittedNoNoNot visible via API
NewNewSubmit accepted; admission and content certification beginNoNoSubmitted / SubmittedAdvanced once certifiedStore eviId and LookupKey for reconciliation
ReadyReadyValidated, certified, and ready for sendingNoNoReadyOptional UI transition
DispatchedDispatchedSending has been requested; the message is ready for the sender componentNoNoDispatchedUpdate tracking; not yet sent or delivered
SentSentRecipient's mail server accepted the messageNoNoSentTransmissionResultReconcile against your in-flight set
DeliveredDeliveredDelivery confirmation was receivedNoNoDeliveredDeliveryResultSurface "delivered" to the operator
ReadReadRecipient opened the message (when supported)NoYes — fires on each open; deduplicate on IdentifierReadRead (generated once regardless)Treat as best-effort; deduplicate on Identifier
RepliedRepliedRecipient accepted or rejected (when configured)NoNoRepliedCommitted / CommittedAdvancedBranch on Kind from the callback
ClosedClosedTracking ended; outcome assignedYesNoClosedClosed / ClosedAdvanced, often Complete / CompleteAdvancedMark the transaction terminal
FailedFailedDelivery failure occurred; retries may still followNoYes — fires on each retry attemptFailedFailed (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.


Evidence and affidavits

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.

When each affidavit is generated

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 valueTriggered atNotesAffidavitPublished callback fires?
SubmittedNew → Ready (content certified)Certifies admission, content, and metadataYes, if in PushNotificationFilter
SubmittedAdvancedNew → ReadyAdvanced variant; includes rendered bodyYes
TransmissionResultSent (SMTP response received)Certifies the handoff to the recipient mail serverYes
DeliveryResultDelivered (delivery confirmation/result received)Certifies the delivery resultYes
ReadRead (recipient opened the message)Only generated once, even if open is detected multiple timesYes
CommittedReplied (recipient accepted or rejected)Certifies the acceptance or rejection actionYes
CommittedAdvancedRepliedAdvanced variant of the commitment affidavitYes
ClosedClosedCertifies the end of trackingYes
ClosedAdvancedClosedAdvanced variantYes
CompleteClosedCertifies the full chain from submission to closure, regardless of final resultYes
CompleteAdvancedClosedAdvanced variant of the complete lifecycle affidavit, regardless of final resultYes
OnDemandOn request via POST /v1/EviMail/AffidavitRequestRequires OnDemand in AffidavitKinds at submit time and an eligible, non-closed communicationYes, with RequestId in AdditionalData
EventTechnical events when generated by the configured affidavit kindsInternal technical record for events that do not have a more specific affidavit kindYes
FailedClosed following terminal failureOnly when the final outcome is failureYes

Key things to know:

  • Every generated affidavit fires an AffidavitPublished callback to the original PushNotificationUrl, but only if AffidavitPublished is in PushNotificationFilter. The callback includes AffidavitId, AffidavitKind, and AffidavitName in AdditionalData.
  • Affidavit generation is asynchronous. The affidavit is not available instantly after the state transition — wait for the AffidavitPublished callback or poll with IncludeAffidavits=true on Query.
  • To enable on-demand affidavits, include OnDemand in AffidavitKinds at submit time. This cannot be enabled retroactively.
  • On-demand affidavit requests are rejected when the communication is Draft, already Closed, 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.


Querying status

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.


First-call walkthrough

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.

What you need

  • API credentialsEVI_USER and EVI_PASS for 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 XmissionDetails and Comments) — 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.

Step 1 — Send your first communication

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.

Step 2 — Verify the state progresses

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.

Step 3 — Confirm delivery

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.

Step 4 — Download the affidavit

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.

Step 5 — Test the failure path

Resubmit using an address that will fail delivery — confirm this address with your Namirial Notify contact. Verify that:

  1. The communication eventually reaches "state": "Closed" with "outcome": "Failed".
  2. You receive both Kind: Failed and Kind: Closed callbacks. They can be retried or arrive out of order, so reconcile them with Query.
  3. Your system handles Outcome: Failed without triggering an automatic resubmit.

This exercises your error-handling code before any real communications go through.


Integration checklist

  • Set LookupKey on every Submit and persist eviId from the response.
  • Send X-Evi-IdempotencyToken (UUIDv4) on every Submit. Treat 202 Accepted as success and 409 Conflict as "retry with the same token after a short backoff".
  • Use HTTPS for PushNotificationUrl so you receive XmissionDetails and Comments.
  • 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 LookupKey and use IncludeAffidavits=true when you need affidavit metadata.
  • Include OnDemand in AffidavitKinds at submit time if you intend to call AffidavitRequest later. This cannot be added retroactively.
  • Persist AffidavitId from AffidavitPublished callbacks. Affidavits are the legal artifact you will need during disputes.
  • Validate PushNotificationFilter values at submit time. Unsupported or repeated values are rejected by the API, so catch typos before submitting.
  • Test the happy path and the FailedClosed (Outcome: Failed) path in pre-production before going live.

Troubleshooting

SymptomLikely causesWhat to checkWhat to do
No callbacks receivedPushNotificationUrl missing on Submit; PushNotificationFilter omits the Kind you expect; endpoint returned non-2xx and retries exhausted; firewall blocks Namirial Notify egressEvents via Query; server access logs for the callback IdentifierConfirm filter and URL; make endpoint publicly reachable; use Query polling as fallback
Message stays in Dispatched or SentSender processing still pending; recipient MTA slow or greylisting; mailbox fullTimestamps in Query response: dispatchedOn, sentOn, deliveredOnWait for Closed; do not resubmit
deliveredOn is missing but readOn is presentdeliveredOn depends on a DSN from the recipient's mail server, which many servers never send; readOn is recorded independently from supported open or read signalsBoth timestamps in the Query responseThis 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 emailSpam filter; recipient address typo; alias forwarding brokeDelivered 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 callbacksEndpoint timed out or returned non-2xx; platform retriedIdentifier field — duplicates share the same valueDeduplicate on Identifier; make the callback handler idempotent
Affidavit not availableGeneration is asynchronous; AffidavitPublished has not fired yet; OnDemand was not included in AffidavitKinds at submit (on-demand requests blocked)Query with IncludeAffidavits=trueWait for AffidavitPublished callback; for on-demand, if RequestId was returned but no callback arrived, contact support with that RequestId
Submit → 400 Bad RequestMissing required field (Subject, Body, or Recipient.EmailAddress); invalid or unsupported enum value (e.g. CertificationLevel not on account); attachment too largeresponseStatus.errors[] for field-level detailsFix the flagged field; retry with a new idempotency token
Submit → 401 UnauthorizedWrong environment base URL; credentials rotatedAuthorization header value; confirm target environmentRe-issue credentials through your Namirial Notify contact
Submit → 403 ForbiddenAccount not provisioned for EviMail; From address not permitted; restricted header in requestresponseStatus.messageContact your Namirial Notify account manager
Submit → 409 ConflictAnother Submit with the same X-Evi-IdempotencyToken is still in flightBack off briefly; retry with the same token; do not generate a new one
Callback payload missing expected fieldsSubscribed to a different Kind than the one you are reading; field is HTTPS-only and URL is HTTP; mis-routing on KindKind and EvidenceType on the incoming payloadRoute on Kind + EvidenceType first; switch PushNotificationUrl to HTTPS to unlock XmissionDetails and Comments; see Callbacks and webhooks for full field tables