Skip to content

Email

Transactional email with templates, domain verification and delivery tracking.

1. Overview

Base path: https://api.infrai.cc/v1/email
Auth header: Authorization: Bearer $INFRAI_API_KEY
bash
# Call any /v1/email capability over raw HTTP — no SDK to install.
# curl:
curl https://api.infrai.cc/v1/email/... \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json"

2. Methods (19)

2.1email.send

POST /v1/email/send

Send a transactional email; supports templates and attachments.

Parameters

NameTypeRequiredDescription
tostring | string[]
Required
Recipient address or list of addresses.
subjectstring
Required
Subject line.
textstringOptionalPlain-text body.
htmlstringOptionalHTML body.
fromstringOptionalSender address (requires a verified domain).
ccstring[]OptionalCarbon-copy addresses.
bccstring[]OptionalBlind carbon-copy addresses.
template_idstringOptionalTemplate id to render instead of a body.
template_varsRecord<string, unknown>OptionalVariables passed to the template.
attachmentsArray<{ filename, content, mime? }>OptionalFiles to attach.
vendorstringOptionalPin a specific vendor instead of auto-routing.
idempotency_keystringOptionalOptional dedup key; identical retries return the same result.

Returns

EmailRecord { email_id, state, to, subject, vendor, created_at }
NameTypeDescription
message_idstringUnique identifier for this message
pattern: ^msg_[A-Za-z0-9]{20,}$
vendor_message_idstring | nullMessage identifier assigned by the upstream vendor
from_usedstringSender email address that was actually used for delivery
mode"default_vendor" | "verified_domain"Delivery mode or operation mode
scheduled_atstring | nullISO 8601 timestamp when the resource is scheduled to activate
format: date-time
accepted_recipientsstring[]List of recipient email addresses that were accepted
suppressed_recipientsstring[]List of recipient email addresses that were suppressed
metadataobject | nullCost/vendor disclosure for this send (cost-transparency contract surface). A superset of kernel ResultMetadata that also carries the email-specific `mode` field; present once a vendor route has been resolved (absent only if all recipients were pre-suppressed before delivery was attempted... still normally present with cost_usd=0 in that case).
metadata.request_idstringUUID v7.
metadata.trace_idstringDistributed tracing identifier
metadata.timestampstringUnix timestamp of the data point
format: date-time
metadata.latency_msintegerLatency of the operation in milliseconds
≥ 0
metadata.entry_formanyEntry point format (rest, mcp, sdk)
metadata.cost_usdnumberCost of this operation in USD
≥ 0
metadata.cost_cnynumberCost in CNY for this request
≥ 0
metadata.vendorstringAdapter name; references VendorRegistry.
metadata.vendor_region"china" | "western"Vendor region where the request was processed
metadata.markup_pctnumberMarkup percentage applied on top of vendor cost
metadata.mode"default_vendor" | "verified_domain"Email delivery mode this send resolved to (email-specific field not present on the generic kernel ResultMetadata).

Example

One-time prep (each example is assumed to be complete):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/email/send \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to": "alice@example.com", "subject": "Welcome", "html": "<p>Hi!</p>"}'

2.2email.get

GET /v1/email/get/{id}

Fetch a single email record by id.

Parameters

NameTypeRequiredDescription
idstring
Required
The email record id.

Returns

EmailRecord
NameTypeDescription
message_idstringArchive id of the message (msg_ + hex).
pattern: ^msg_[A-Za-z0-9]{12,}$
statestringAggregate state — see enums/email_state.yaml.
channel"email"Delivery channel of the archived record.
toanyRecipient(s) the message was sent to (string or array, as submitted).
vendorstringServing vendor that dispatched the message.
created_atnumber | stringEpoch seconds (or ISO-8601) when the message was archived.
per_recipient_stateobjectOPTIONAL — map of recipient_email -> per-recipient state (populated only when a delivery-event webhook pipeline is wired).
first_event_atstringOPTIONAL — first delivery-event timestamp (webhook-derived).
format: date-time
last_event_atstringOPTIONAL — latest delivery-event timestamp (webhook-derived).
format: date-time
countsobjectOPTIONAL — per-event-type tallies (delivered/bounced/opened/clicked/...), webhook-derived.

Example

One-time prep (each example is assumed to be complete):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X GET https://api.infrai.cc/v1/email/get/ID \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.3email.suppression.add

POST /v1/email/suppression/add

Add an address to the suppression list.

Returns

SuppressionRecord
NameTypeDescription
emailstringEmail address
format: email
reason"hard_bounce" | "soft_bounce_5x" | "complained" | "unsubscribed" | "invalid" | "manual" | "user_request"Reason for the current state or action
added_atstringISO 8601 timestamp when this resource was added
format: date-time
last_attempt_atstring | nullLast time a send was blocked by this entry.
format: date-time
attempt_count_blockedinteger | nullNumber of delivery attempts blocked by this suppression
≥ 0
notesstring | nullFree-text notes about this suppression
scope"account" | "domain"Scope of applicability for this resource
domain_scopestring | nullWhen scope=domain, the specific verified domain.

Example

One-time prep (each example is assumed to be complete):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/email/suppression/add \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email": "user@example.com"}'

2.4email.domain.verify

POST /v1/email/domain/verify

Verify a sending domain and return required DNS records.

Parameters

NameTypeRequiredDescription
domainstring
Required
The domain to verify.

Returns

{ verified, records: Array<{ type, name, value }> }
NameTypeDescription
domainstringApex domain, e.g. 'yourdomain.com'.
domain_idstringUnique identifier for this domain
pattern: ^dom_[A-Za-z0-9]{20,}$
status"pending_dns" | "verifying" | "verified" | "failed" | "expired"Current status of this resource
dns_recordsobject[]DNS records required for domain verification
dns_records[].type"TXT" | "CNAME" | "MX" | "A" | "AAAA"Type discriminator for this resource
dns_records[].namestringFully qualified DNS name.
dns_records[].valuestringValue of the DNS record or configuration
dns_records[].purpose"spf" | "dkim" | "tracking" | "dmarc" | "return_path" | "verification"Purpose of the DNS record
dns_records[].ttl_recommendedintegerRecommended TTL in seconds
≥ 60default: 3600
checksobject | nullPer-record check status ('ok'/'pending'/'mismatch'/...).
warm_up_state"not_started" | "in_progress" | "complete" | nullCurrent warm-up state for the domain
daily_limit_currentinteger | nullCurrent daily sending limit
≥ 0
daily_limit_targetinteger | nullTarget daily sending limit after warm-up
≥ 0
created_atstringISO 8601 timestamp when this resource was created
format: date-time
verified_atstring | nullISO 8601 timestamp when verification was completed
format: date-time
expires_atstring | nullDKIM rotation due (1y recommended).
format: date-time
rotatedbooleanPresent only on the response of email.domain.rotate_dkim: true once the DKIM key rotation has been issued (status drops back to pending_dns until the new record is observed in DNS).

Example

One-time prep (each example is assumed to be complete):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/email/domain/verify \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domain": "sample"}'

2.5email.batch.send

POST /v1/email/batch/send

Batch personalized sending, up to 100 different emails share one idempotency_key (batch pass-through, single email is not billed repeatedly).

Parameters

NameTypeRequiredDescription
messagesEmailSendOptions[]
Required
Email array, each item is a complete EmailSendRequest, each with recipient and template variables, ranging from 1 to 100 items.
1–100 items
idempotency_keystringOptionalOptional dedup key; identical retries return the same result.

Returns

BatchSendResult { batch_id, results }
NameTypeDescription
batch_idstringUnique identifier for this batch job
pattern: ^batch_[A-Za-z0-9]{20,}$
resultsobject[]List of individual results from a batch operation
results[].indexintegerPosition of this message in the request messages[] array.
≥ 0
results[].message_idstring | nullNull when this message failed to enqueue.
pattern: ^msg_[A-Za-z0-9]{20,}$
results[].tostring | string[]-
results[].status"accepted" | "suppressed" | "failed"-
results[].errorstring | nullError code when status=failed (e.g. SUPPRESSED_RECIPIENT).

Example

One-time prep (each example is assumed to be complete):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/email/batch/send \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"messages": [{"to": "sample"}]}'

2.6email.cancel

POST /v1/email/cancel/{id}

Cancel an unsent (scheduled) email.

Parameters

NameTypeRequiredDescription
idstring
Required
The email record id.
idempotency_keystringOptionalOptional dedup key; identical retries return the same result.

Returns

EmailStatus { message_id, state, ... }

Example

One-time prep (each example is assumed to be complete):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/email/cancel/ID \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

2.7email.list

GET /v1/email/list

List sent emails for the current account with their latest status.

Parameters

NameTypeRequiredDescription
limitnumberOptionalMaximum items to return.
cursorstringOptionalPagination cursor.

Returns

EmailListResult { items: EmailStatus[], next_cursor?, count }
NameTypeDescription
itemsobject[]Latest status rows for emails sent by this account, newest first.
items[].message_idstringArchive id of the message (msg_ + hex).
pattern: ^msg_[A-Za-z0-9]{12,}$
items[].statestringAggregate state — see enums/email_state.yaml.
items[].channel"email"Delivery channel of the archived record.
items[].toanyRecipient(s) the message was sent to (string or array, as submitted).
items[].vendorstringServing vendor that dispatched the message.
items[].created_atnumber | stringEpoch seconds (or ISO-8601) when the message was archived.
items[].per_recipient_stateobjectOPTIONAL — map of recipient_email -> per-recipient state (populated only when a delivery-event webhook pipeline is wired).
items[].first_event_atstringOPTIONAL — first delivery-event timestamp (webhook-derived).
format: date-time
items[].last_event_atstringOPTIONAL — latest delivery-event timestamp (webhook-derived).
format: date-time
items[].countsobjectOPTIONAL — per-event-type tallies (delivered/bounced/opened/clicked/...), webhook-derived.
countintegerNumber of items in this page
≥ 0
next_cursorstring | nullOpaque cursor to fetch the next page; null when no further page is available.

Example

One-time prep (each example is assumed to be complete):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X GET https://api.infrai.cc/v1/email/list \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.8email.event.list

GET /v1/email/event/list

List the event timeline for one email.

Parameters

NameTypeRequiredDescription
message_idstring
Required
Required. The message_id whose event timeline should be queried.
pattern: ^msg_[A-Za-z0-9]{12,}$e.g. msg_0123456789abcdef
typestringOptionalFilter by event type (e.g. delivered, bounced, opened).
limitnumberOptionalMaximum items to return.
1–100default: 50
cursorstringOptionalPagination cursor.

Returns

{ items: EmailEvent[], next_cursor? }
NameTypeDescription
itemsobject[]List of resource records
items[].type"queued" | "sent" | "delivered" | "opened" | "clicked" | "bounced" | "complained" | "deferred" | "expired" | "cancelled" | "unsubscribed" | "auto_suppressed"Type discriminator for this resource
items[].atstringISO 8601 timestamp of the event
format: date-time
items[].recipientstringRecipient email address
format: email
items[].message_idstring | nullUnique identifier for this message
pattern: ^msg_[A-Za-z0-9]{20,}$
items[].metaobject | nullEvent-specific metadata (ip / user_agent / url / bounce_type / reason).
countintegerNumber of items in this page
≥ 0
next_cursorstring | nullPass back into event.list() to fetch the next page.

Example

One-time prep (each example is assumed to be complete):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X GET https://api.infrai.cc/v1/email/event/list?message_id=msg_0123456789abcdef \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.9email.suppression.check

GET /v1/email/suppression/check/{email}

Check whether a certain recipient address is in the suppression list.

Parameters

NameTypeRequiredDescription
emailstring
Required
Recipient email address.

Returns

SuppressionCheckResult { is_suppressed, record? }
NameTypeDescription
emailstringThe email address that was checked.
suppressedbooleanWhether the address is currently suppressed
reason"hard_bounce" | "soft_bounce_5x" | "complained" | "unsubscribed" | "invalid" | "manual" | "user_request"Reason for the current suppression. Present only when suppressed=true.
added_atstringISO 8601 timestamp when this suppression was added. Present only when suppressed=true.
format: date-time
last_attempt_atstring | nullLast time a send was blocked by this entry. Present only when suppressed=true.
format: date-time
attempt_count_blockedinteger | nullNumber of delivery attempts blocked by this suppression. Present only when suppressed=true.
≥ 0
notesstring | nullFree-text notes about this suppression. Present only when suppressed=true.
scope"account" | "domain"Scope of applicability for this suppression entry. Present only when suppressed=true.
domain_scopestring | nullWhen scope=domain, the specific verified domain. Present only when suppressed=true.

Example

One-time prep (each example is assumed to be complete):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X GET https://api.infrai.cc/v1/email/suppression/check/EMAIL \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.10email.suppression.list

GET /v1/email/suppression/list

List the recipient addresses in the suppressed list.

Parameters

NameTypeRequiredDescription
reasonstringOptionalFilter by suppression reason (e.g. bounce, complaint, manual).
limitnumberOptionalMaximum items to return.
cursorstringOptionalPagination cursor.

Returns

{ items: SuppressionRecord[], next_cursor? }
NameTypeDescription
itemsobject[]List of resource records
items[].emailstringEmail address
format: email
items[].reason"hard_bounce" | "soft_bounce_5x" | "complained" | "unsubscribed" | "invalid" | "manual" | "user_request"Reason for the current state or action
items[].added_atstringISO 8601 timestamp when this resource was added
format: date-time
items[].last_attempt_atstring | nullLast time a send was blocked by this entry.
format: date-time
items[].attempt_count_blockedinteger | nullNumber of delivery attempts blocked by this suppression
≥ 0
items[].notesstring | nullFree-text notes about this suppression
items[].scope"account" | "domain"Scope of applicability for this resource
items[].domain_scopestring | nullWhen scope=domain, the specific verified domain.
countintegerNumber of items in this page
≥ 0
next_cursorstring | nullOpaque cursor to fetch the next page; null/absent if this is the last page

Example

One-time prep (each example is assumed to be complete):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X GET https://api.infrai.cc/v1/email/suppression/list \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.11email.suppression.delete

DELETE /v1/email/suppression/delete/{email}

Remove an address from the suppression list and resume delivery to it.

Parameters

NameTypeRequiredDescription
emailstring
Required
Recipient email address.
idempotency_keystringOptionalOptional dedup key; identical retries return the same result.

Returns

{ deleted: boolean }
NameTypeDescription
emailstring | nullEmail address removed from suppression list
deletedbooleanWhether the suppression entry was removed (same value as `found`: the entry existed and was removed from the suppression store).
foundbooleanWhether a suppression entry existed for this email prior to the delete call.

Example

One-time prep (each example is assumed to be complete):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X DELETE https://api.infrai.cc/v1/email/suppression/delete/EMAIL \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.12email.domain.list

GET /v1/email/domain/list

List the email domain names added under the account.

Parameters

NameTypeRequiredDescription
limitnumberOptionalMaximum items to return.
cursorstringOptionalPagination cursor.

Returns

{ items: DomainVerification[], next_cursor? }
NameTypeDescription
itemsobject[]Configured sender domains with verification state
items[].domainstringApex domain, e.g. 'yourdomain.com'.
items[].domain_idstringUnique identifier for this domain
pattern: ^dom_[A-Za-z0-9]{20,}$
items[].status"pending_dns" | "verifying" | "verified" | "failed" | "expired"Current status of this resource
items[].dns_recordsobject[]DNS records required for domain verification
items[].dns_records[].type"TXT" | "CNAME" | "MX" | "A" | "AAAA"Type discriminator for this resource
items[].dns_records[].namestringFully qualified DNS name.
items[].dns_records[].valuestringValue of the DNS record or configuration
items[].dns_records[].purpose"spf" | "dkim" | "tracking" | "dmarc" | "return_path" | "verification"Purpose of the DNS record
items[].dns_records[].ttl_recommendedintegerRecommended TTL in seconds
≥ 60default: 3600
items[].checksobject | nullPer-record check status ('ok'/'pending'/'mismatch'/...).
items[].warm_up_state"not_started" | "in_progress" | "complete" | nullCurrent warm-up state for the domain
items[].daily_limit_currentinteger | nullCurrent daily sending limit
≥ 0
items[].daily_limit_targetinteger | nullTarget daily sending limit after warm-up
≥ 0
items[].created_atstringISO 8601 timestamp when this resource was created
format: date-time
items[].verified_atstring | nullISO 8601 timestamp when verification was completed
format: date-time
items[].expires_atstring | nullDKIM rotation due (1y recommended).
format: date-time
items[].rotatedbooleanPresent only on the response of email.domain.rotate_dkim: true once the DKIM key rotation has been issued (status drops back to pending_dns until the new record is observed in DNS).
total_countintegerTotal number of items across all pages
≥ 0
next_cursorstring | nullPass back into domain.list() to fetch the next page.

Example

One-time prep (each example is assumed to be complete):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X GET https://api.infrai.cc/v1/email/domain/list \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.13email.domain.get

GET /v1/email/domain/get/{domain}

Get the verification status and reputation information of a sending domain name.

Parameters

NameTypeRequiredDescription
domainstring
Required
The domain to verify.

Returns

DomainGetResult { verification, reputation }
NameTypeDescription
verificationobjectDomain verification status and DNS records
verification.domainstringApex domain, e.g. 'yourdomain.com'.
verification.domain_idstringUnique identifier for this domain
pattern: ^dom_[A-Za-z0-9]{20,}$
verification.status"pending_dns" | "verifying" | "verified" | "failed" | "expired"Current status of this resource
verification.dns_recordsobject[]DNS records required for domain verification
verification.dns_records[].type"TXT" | "CNAME" | "MX" | "A" | "AAAA"Type discriminator for this resource
verification.dns_records[].namestringFully qualified DNS name.
verification.dns_records[].valuestringValue of the DNS record or configuration
verification.dns_records[].purpose"spf" | "dkim" | "tracking" | "dmarc" | "return_path" | "verification"Purpose of the DNS record
verification.dns_records[].ttl_recommendedintegerRecommended TTL in seconds
≥ 60default: 3600
verification.checksobject | nullPer-record check status ('ok'/'pending'/'mismatch'/...).
verification.warm_up_state"not_started" | "in_progress" | "complete" | nullCurrent warm-up state for the domain
verification.daily_limit_currentinteger | nullCurrent daily sending limit
≥ 0
verification.daily_limit_targetinteger | nullTarget daily sending limit after warm-up
≥ 0
verification.created_atstringISO 8601 timestamp when this resource was created
format: date-time
verification.verified_atstring | nullISO 8601 timestamp when verification was completed
format: date-time
verification.expires_atstring | nullDKIM rotation due (1y recommended).
format: date-time
verification.rotatedbooleanPresent only on the response of email.domain.rotate_dkim: true once the DKIM key rotation has been issued (status drops back to pending_dns until the new record is observed in DNS).
reputationobject | nullNull until the domain is verified and has begun warming up.
reputation.domainstringDomain name
reputation.tier"warming_up" | "established" | "trusted" | "throttled" | "suspended"Current subscription tier (standard / pro / enterprise)
reputation.current_daily_capintegerCurrent daily sending cap
≥ 0
reputation.used_todayintegerNumber of emails sent today
≥ 0
reputation.bounce_rate_30dnumberBounce rate over the last 30 days
0–1
reputation.complaint_rate_30dnumberComplaint rate over the last 30 days
0–1
reputation.days_in_current_tierintegerDays in the current warm-up tier
≥ 0
reputation.next_tier"warming_up" | "established" | "trusted" | "throttled" | "suspended" | nullNext warm-up tier
reputation.next_tier_requirementsobject | nullConcrete thresholds + remaining-duration to upgrade.
reputation.throttle_risk"low" | "medium" | "high"Current risk of being throttled based on recent domain reputation metrics.

Example

One-time prep (each example is assumed to be complete):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X GET https://api.infrai.cc/v1/email/domain/get/DOMAIN \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.14email.domain.delete

DELETE /v1/email/domain/delete/{domain}

Delete an added sending domain name.

Parameters

NameTypeRequiredDescription
domainstring
Required
The domain to verify.
idempotency_keystringOptionalOptional dedup key; identical retries return the same result.

Returns

{ deleted: boolean }
NameTypeDescription
domainstring | nullDomain name that was deleted
deletedbooleanWhether the domain was deleted (same value as `found`: the domain existed and was removed from the self-managed sender-domain store).
foundbooleanWhether a domain verification record existed for this domain prior to the delete call.

Example

One-time prep (each example is assumed to be complete):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X DELETE https://api.infrai.cc/v1/email/domain/delete/DOMAIN \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.15email.domain.rotate_dkim

POST /v1/email/domain/rotate_dkim/{domain}

Rotate DKIM keys for the sending domain name and return new DNS records that need to be configured.

Parameters

NameTypeRequiredDescription
domainstring
Required
The domain to verify.
idempotency_keystringOptionalOptional dedup key; identical retries return the same result.

Returns

DomainVerification { domain, status, dns_records, ... }
NameTypeDescription
domainstringApex domain, e.g. 'yourdomain.com'.
domain_idstringUnique identifier for this domain
pattern: ^dom_[A-Za-z0-9]{20,}$
status"pending_dns" | "verifying" | "verified" | "failed" | "expired"Current status of this resource
dns_recordsobject[]DNS records required for domain verification
dns_records[].type"TXT" | "CNAME" | "MX" | "A" | "AAAA"Type discriminator for this resource
dns_records[].namestringFully qualified DNS name.
dns_records[].valuestringValue of the DNS record or configuration
dns_records[].purpose"spf" | "dkim" | "tracking" | "dmarc" | "return_path" | "verification"Purpose of the DNS record
dns_records[].ttl_recommendedintegerRecommended TTL in seconds
≥ 60default: 3600
checksobject | nullPer-record check status ('ok'/'pending'/'mismatch'/...).
warm_up_state"not_started" | "in_progress" | "complete" | nullCurrent warm-up state for the domain
daily_limit_currentinteger | nullCurrent daily sending limit
≥ 0
daily_limit_targetinteger | nullTarget daily sending limit after warm-up
≥ 0
created_atstringISO 8601 timestamp when this resource was created
format: date-time
verified_atstring | nullISO 8601 timestamp when verification was completed
format: date-time
expires_atstring | nullDKIM rotation due (1y recommended).
format: date-time
rotatedbooleanPresent only on the response of email.domain.rotate_dkim: true once the DKIM key rotation has been issued (status drops back to pending_dns until the new record is observed in DNS).

Example

One-time prep (each example is assumed to be complete):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/email/domain/rotate_dkim/DOMAIN \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

2.16email.template.create

POST /v1/email/template/create

Create an email template.

Parameters

NameTypeRequiredDescription
namestring
Required
Template name, unique within the account.
1–128 chars
subjectstring
Required
Theme template, which can contain {'{var}'} placeholders.
htmlstring
Required
HTML body template, which can contain {'{var}'}, {'{#section}'}, {'{^inverted}'}.
body_textstringOptionalPlain text alternative body.
variablesRecord<string, string>OptionalDeclared variables and types, such as {name: 'string'}.
default_varsRecord<string, unknown>OptionalThe default value used when the variable is missing when sent.
tagsstring[]OptionalTemplate tag list.
idempotency_keystringOptionalOptional dedup key; identical retries return the same result.

Returns

Template { template_id, name, subject, html, ... }
NameTypeDescription
template_idstringIdentifier of the template used for rendering
pattern: ^tmpl_[A-Za-z0-9]{20,}$
namestringUnique within account.
1–128 chars
subjectstringMay contain double-brace placeholders (e.g. var).
htmlstringHTML body; may contain double-brace placeholders (var, #section, ^inverted).
body_textstring | nullPlain-text alternative.
variablesobject | nullDeclared variables: name with type 'string', 'int', 'bool', 'array', or 'object'.
default_varsobject | nullDefaults used when var missing in send().
tagsstring[] | nullTags for categorization and filtering
created_atstringISO 8601 timestamp when this resource was created
format: date-time
updated_atstringISO 8601 timestamp when this resource was last updated
format: date-time

Example

One-time prep (each example is assumed to be complete):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/email/template/create \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "example", "subject": "sample", "html": "<h1>Hello from infrai</h1>"}'

2.17email.template.update

PATCH /v1/email/template/update/{id}

Update an existing email template.

Parameters

NameTypeRequiredDescription
idstring
Required
Template id to render instead of a body.
subjectstringOptionalTheme template, which can contain {'{var}'} placeholders.
htmlstringOptionalHTML body template, which can contain {'{var}'}, {'{#section}'}, {'{^inverted}'}.
body_textstringOptionalPlain text alternative body.
variablesRecord<string, string>OptionalDeclared variables and types, such as {name: 'string'}.
default_varsRecord<string, unknown>OptionalThe default value used when the variable is missing when sent.
tagsstring[]OptionalTemplate tag list.
idempotency_keystringOptionalOptional dedup key; identical retries return the same result.

Returns

Template { template_id, name, subject, html, ... }
NameTypeDescription
template_idstringIdentifier of the template used for rendering
pattern: ^tmpl_[A-Za-z0-9]{20,}$
namestringUnique within account.
1–128 chars
subjectstringMay contain double-brace placeholders (e.g. var).
htmlstringHTML body; may contain double-brace placeholders (var, #section, ^inverted).
body_textstring | nullPlain-text alternative.
variablesobject | nullDeclared variables: name with type 'string', 'int', 'bool', 'array', or 'object'.
default_varsobject | nullDefaults used when var missing in send().
tagsstring[] | nullTags for categorization and filtering
created_atstringISO 8601 timestamp when this resource was created
format: date-time
updated_atstringISO 8601 timestamp when this resource was last updated
format: date-time

Example

One-time prep (each example is assumed to be complete):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X PATCH https://api.infrai.cc/v1/email/template/update/ID \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

2.18email.template.delete

DELETE /v1/email/template/delete/{id}

Delete an email template.

Parameters

NameTypeRequiredDescription
idstring
Required
Template id to render instead of a body.
idempotency_keystringOptionalOptional dedup key; identical retries return the same result.

Returns

{ deleted: boolean }
NameTypeDescription
template_idstring | nullIdentifier of the deleted template
deletedbooleanWhether the template was deleted (same value as `found`: the template existed and was removed from the template store).
foundbooleanWhether a template existed with this id prior to the delete call.

Example

One-time prep (each example is assumed to be complete):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X DELETE https://api.infrai.cc/v1/email/template/delete/ID \
  -H "Authorization: Bearer $INFRAI_API_KEY"

2.19email.template.preview

POST /v1/email/template/preview/{id}

Renders the template with the given variables, previewing themes, HTML, text and missing variables.

Parameters

NameTypeRequiredDescription
idstring
Required
Template id to render instead of a body.
varsRecord<string, unknown>
Required
Variable values ​​used for rendering will be merged with the template''s default_vars.

Returns

TemplatePreview { rendered_subject, rendered_html, rendered_text, missing_vars }
NameTypeDescription
rendered_subjectstringRendered subject line with variables substituted
rendered_htmlstringRendered HTML body with variables substituted
rendered_textstring | nullRendered plain text body with variables substituted
missing_varsstring[]Variables referenced by template but missing from input + default_vars.

Example

One-time prep (each example is assumed to be complete):

bash
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."
bash
curl -X POST https://api.infrai.cc/v1/email/template/preview/ID \
  -H "Authorization: Bearer $INFRAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"vars": {}}'
Advanced: pin a vendor

By default infrai routes each call to the best available provider — you do not pick a vendor. As an escape hatch, this capability accepts an optional vendor parameter to pin one specific provider. Every live vendor for this capability is available in real time from the discovery endpoint for the capability id — see the discovery API.

GET /v1/discovery/{capability}

email.send

3. All capabilities

Every routed capability in this module — the complete public REST contract. The methods above are the guided walkthrough; this index is the full reference.

email.batch.sendPOST /v1/email/batch/send

Send up to 100 personalized emails under one idempotency_key (batch passthrough, not billed per message).

Parameters (2)
NameTypeRequiredDescription
messagesobject[]RequiredEach entry is a full EmailSendRequest with its own recipients / template_vars.
1–100 items
idempotency_keystring | nullOptionalOne key for the whole batch; per-message sends are not re-charged.
email.cancelPOST /v1/email/cancel/{id}

Cancel a scheduled email that has not yet been sent.

Parameters (2)
NameTypeRequiredDescription
idstringRequiredPath parameter.
idempotency_keystring | nullOptionalClient-provided idempotency key; prevents duplicate execution on retry
email.domain.deleteDELETE /v1/email/domain/delete/{domain}

Delete a previously added sender domain.

Parameters (1)
NameTypeRequiredDescription
domainstringRequiredPath parameter.
email.domain.getGET /v1/email/domain/get/{domain}

Get the verification status and reputation of a sender domain.

Parameters (1)
NameTypeRequiredDescription
domainstringRequiredPath parameter.
email.domain.listGET /v1/email/domain/list

List the sender domains added to the account.

No request parameters.

email.domain.rotate_dkimPOST /v1/email/domain/rotate_dkim/{domain}

Rotate DKIM for a sender domain and return the new DNS records.

Parameters (2)
NameTypeRequiredDescription
domainstringRequiredPath parameter.
idempotency_keystring | nullOptionalClient-provided idempotency key; prevents duplicate execution on retry
email.domain.verifyPOST /v1/email/domain/verify

Verify a sender domain's DNS records to complete verification.

Parameters (2)
NameTypeRequiredDescription
domainstringRequiredSending domain to verify (e.g. mail.example.com).
idempotency_keystring | nullOptionalClient-provided idempotency key; prevents duplicate execution on retry
email.event.listGET /v1/email/event/list

List the delivery event timeline for one email; message_id is required.

Parameters (3)
NameTypeRequiredDescription
message_idstringRequiredInfrai message id returned by email.send.
pattern: ^msg_[A-Za-z0-9]{12,}$e.g. msg_0123456789abcdef
typestringOptionalOptional delivery-event type filter.
limitintegerOptionalMaximum events to return.
1–100default: 50
email.getGET /v1/email/get/{id}

Get the delivery details of one email by message_id.

Parameters (1)
NameTypeRequiredDescription
idstringRequiredPath parameter.
email.listGET /v1/email/list

List emails sent by the current account with their latest status.

No request parameters.

email.sendPOST /v1/email/send

Send a transactional email (inline body/HTML or a template) with tracking; idempotent.

Parameters (21)
NameTypeRequiredDescription
tostring | string[]RequiredRecipient address, or an array of addresses for multiple recipients.
ccstring[]OptionalCarbon copy recipients
bccstring[]OptionalBlind carbon copy recipients
fromstring | nullOptionalOptional. Omit to use Infrai's default sender on send.infrai.cc. If you provide a custom-domain sender, that domain must be verified first.
from_display_namestring | nullOptionalDisplay name for the sender
reply_tostring | nullOptionalReply-to email address
subjectstring | nullOptionalEmail subject line
bodystring | nullOptionalPlain text body.
htmlstring | nullOptionalHTML body of the email
template_idstring | nullOptionalIdentifier of the template used for rendering
template_varsobject | nullOptionalVariables to substitute in the template
attachmentsobject[]OptionalList of email attachments
headersobject | nullOptionalCustom HTTP headers to include in requests or responses
tagsstring[]OptionalTags for categorization and filtering
track_opensbooleanOptionalWhether to track email opens
default: false
track_clicksbooleanOptionalWhether to track link clicks in the email
default: false
scheduled_atstring | nullOptionalISO 8601 timestamp when the resource is scheduled to activate
format: date-time
idempotency_keystring | nullOptionalClient-provided idempotency key; prevents duplicate execution on retry
vendorstring | nullOptionalPin to a specific vendor.
message_class"transactional" | "marketing"OptionalSemantic class of the message. Only transactional is currently live; marketing is reserved and fails closed.
default: "transactional"
auto_unsubscribe_linkboolean | nullOptionalWhether to append a signed unsubscribe link. Transactional messages omit it by default; marketing-like content may still be forced to include it.
email.suppression.addPOST /v1/email/suppression/add

Add a recipient address to the suppression list to stop future delivery; idempotent.

Parameters (6)
NameTypeRequiredDescription
emailstringRequiredEmail address
format: email
reason"hard_bounce" | "soft_bounce_5x" | "complained" | "unsubscribed" | "invalid" | "manual" | "user_request"OptionalReason for the current state or action
default: "manual"
scope"account" | "domain"OptionalScope of applicability for this resource
default: "account"
domain_scopestring | nullOptionalWhen scope=domain, the specific verified domain.
notesstring | nullOptionalFree-text notes about this suppression
idempotency_keystring | nullOptionalClient-provided idempotency key; prevents duplicate execution on retry
email.suppression.checkGET /v1/email/suppression/check/{email}

Check whether an address is on the suppression list.

Parameters (1)
NameTypeRequiredDescription
emailstringRequiredPath parameter.
email.suppression.deleteDELETE /v1/email/suppression/delete/{email}

Remove an address from the suppression list to resume delivery.

Parameters (1)
NameTypeRequiredDescription
emailstringRequiredPath parameter.
email.suppression.listGET /v1/email/suppression/list

List recipient addresses on the suppression list.

No request parameters.

email.template.createPOST /v1/email/template/create

Create an email template.

Parameters (8)
NameTypeRequiredDescription
namestringRequiredUnique within account.
1–128 chars
subjectstringRequiredMay contain double-brace var placeholders.
htmlstringRequiredHTML body; may contain double-brace var, double-brace #section, double-brace ^inverted.
body_textstring | nullOptionalPlain-text alternative.
variablesobject | nullOptionalDeclared variables: { name: 'string' | 'int' | 'bool' | 'array' | 'object' }.
default_varsobject | nullOptionalDefaults used when var missing in send().
tagsstring[] | nullOptionalTags for categorization and filtering
idempotency_keystring | nullOptionalClient-provided idempotency key; prevents duplicate execution on retry
email.template.deleteDELETE /v1/email/template/delete/{id}

Delete an email template.

Parameters (1)
NameTypeRequiredDescription
idstringRequiredPath parameter.
email.template.previewPOST /v1/email/template/preview/{id}

Render and preview a template with the given variables.

Parameters (2)
NameTypeRequiredDescription
idstringRequiredPath parameter.
varsobjectRequiredVariable values merged with the template's default_vars before rendering.
email.template.updatePATCH /v1/email/template/update/{id}

Update an existing email template.

Parameters (8)
NameTypeRequiredDescription
idstringRequiredPath parameter.
subjectstring | nullOptionalMay contain double-brace var placeholders.
htmlstring | nullOptionalHTML body; may contain double-brace var, double-brace #section, double-brace ^inverted.
body_textstring | nullOptionalPlain-text alternative.
variablesobject | nullOptionalTemplate variable definitions
default_varsobject | nullOptionalDefault variable values for the template
tagsstring[] | nullOptionalTags for categorization and filtering
idempotency_keystring | nullOptionalClient-provided idempotency key; prevents duplicate execution on retry

4. End-to-end example

A production-style walkthrough of this module: configure once, then run the flow. It exercises most of the module's APIs.

A copy-paste-runnable single-file Python program (stdlib only, no SDK): set your INFRAI_API_KEY, run it, and walk this module's core flow with REAL billed calls — later steps reuse real fields returned by earlier ones. The 12-line helper is the entire integration.

python
#!/usr/bin/env python3
"""Infrai · comm-email — runnable real-app example (single file, zero deps).

Copy this file, set your key, run it: every step is a REAL call to
api.infrai.cc, billed at the real (tiny) per-call price, printing the
live JSON response. Get a key at https://infrai.cc/login (Google/
GitHub sign-in grants $2 free credit); add funds at
https://infrai.cc/billing. No SDK — the 12-line helper below is the
entire integration."""
import json
import os
from urllib import error, request

KEY = os.environ.get("INFRAI_API_KEY") or "ifr_..."  # <- your key
BASE = "https://api.infrai.cc"


# Same raw HTTPS POST/GET as every per-method example on this page —
# wrapped once for reuse. There is nothing else to it: no SDK.
def infrai(method, path, body=None):
    req = request.Request(
        BASE + path, method=method,
        data=json.dumps(body).encode() if body is not None else None,
        headers={"Authorization": f"Bearer {KEY}",
                 "Content-Type": "application/json"})
    try:
        with request.urlopen(req, timeout=60) as r:
            return json.loads(r.read())
    except error.HTTPError as e:
        return json.loads(e.read())


def show(label, resp):
    print(f"\n== {label} ==")
    print(json.dumps(resp, indent=2, ensure_ascii=False))
    return resp


# 1) email.send — POST /v1/email/send · Send a transactional email (inline body/HTML or a template) with tracking; idempotent.
ask1 = input("Your email address (sends a real email): ").strip()
r1 = show("email.send", infrai("POST", "/v1/email/send", {"to":ask1}))

# 2) email.get — GET /v1/email/get/{id} · Get the delivery details of one email by message_id.
id_2 = (r1.get("data") or {}).get("message_id") or ""
r2 = show("email.get", infrai("GET", f"/v1/email/get/{id_2}"))

# 3) email.event.list — GET /v1/email/event/list · List the delivery event timeline for one email; message_id is required.
message_id_3 = (r2.get("data") or {}).get("message_id") or ""
r3 = show("email.event.list", infrai("GET", f"/v1/email/event/list?message_id={message_id_3}"))

5. Developer guides

Move from endpoint details to complete workflows, production patterns and troubleshooting guides verified against the live API.

Email developer guides