emailChannel(An email channel adapter:options?):EmailChannelAdapter
inbound(payload) normalises a received mail,
send(request) replies in its thread through the inbox’s reply action.
Parameters
Returns
EmailChannelAdapter
Over the Email API
emailChannel() is exported from @telnyx/agent-harness/channels, from 0.1.0-beta.3. The adapter it returns is a ChannelAdapter with channel: "email", for createChannelRouter(). It handles the email.received webhook of an inbox. The host verifies the webhook’s signature and passes its data.payload to inbound().
- Inbox. The inbox is the payload’s
inbox_id. Without one, the adapter looks the recipient up in the account’s inbox list (GET /email_inboxes), ondomainIdwhen it is set, and keeps the list per transport for 60 seconds. A mail for another inbox thaninboxId, or to another address thanaddress, is left alone. - Matching. The reply target is the inbox’s record of the mail. The adapter lists the inbox’s newest messages from the sender (
filter[from],page[size]10) and takes the inbound one the one whoseidormessage_idequals the envelope’sidor its RFC Message-ID (the live payload’smessage_id_header). A Message-ID is compared without its angle brackets. The adapter never matches by subject or recency. - Text. The text given to the model is the record’s
reply_text, else the plain-text body attext_body_urlwith its quoted history dropped, else the message read back from its thread. A body is fetched only overhttpsfrom a host inbodyHosts, through the transport first and then with plainfetch. Redirects are never followed. - Conversation.
conversationIdisemail-<thread id>, elseemail-<sender>.externalMessageIdis the envelope’sid, which a redelivery repeats, so the router’s ledger treats a redelivery as a duplicate. - Reply.
send()posts{ text }toPOST /email_inboxes/{inbox}/messages/{message}/actions/replywith the request’s idempotency key as theIdempotency-Keyheader. The platform addresses and threads the reply.
Unavailable mail
inbound() throws EmailInboundUnavailableError when the inbox has no record that matches the mail, and when a read it needs fails (the inbox list, the inbox, the body or the thread) and no other source has the text. The host answers the webhook with a non-2xx status, such as 503, so the platform delivers it again. A mail that is not this adapter’s, cannot be placed in an inbox or has no text returns undefined; a redelivery would end the same way, so the host acknowledges it.
The platform redelivers a failed
email.received webhook once, about one second later.EmailChannelOptions
Properties address?The address this adapter answers at, for a mail whose inbox is not yet known by id: the inbox is looked up for that recipient. bodyHosts?readonlyoptionaladdress?:EmailAddressScope
Hosts an offloaded body may be fetched from (the host itself or a subdomain, over https). DefaultreadonlyoptionalbodyHosts?: readonlystring[]
EMAIL_BODY_HOSTS.
domainId?
The inbound domain, so the recipient lookup never takes an inbox of the same address on another domain. fetch?readonlyoptionaldomainId?:string
Plain fetch for a public body link, and for an adapter without a transport. Default: the globalreadonlyoptionalfetch?: (url,init?) =>Promise<Response>
fetch. Redirects are never followed.
Parameters
Returns
Promise<Response>
inboxId?
The inbox this adapter answers for and replies from. A mail to another inbox is left alone. now?readonlyoptionalinboxId?:string
The clock forreadonlyoptionalnow?: () =>number
receivedAt. Default Date.now.
Returns
number
onEvent?
Told what happened to each mail. ParametersreadonlyoptionalonEvent?: (event) =>void
Returns
void
transport?
The API. Without one, an offloaded body is fetched with plainreadonlyoptionaltransport?:EmailTransport
fetch,
nothing is read back from the inbox, and send refuses.
EmailAddressScope
The address an adapter answers at: the local part, and the domain when one is named (both compared case-insensitively). Properties domain?usernamereadonlyoptionaldomain?:string
readonlyusername:string
EmailTransport
The Telnyx API, as the adapter calls it: paths are relative to/v2; an absolute URL goes as given. A Telnyx client is one.
Methods
get()
get<Type ParametersT>(path,options?):Promise<T>
Parameters
Returns
Promise<T>
post()
post<Type ParametersT>(path,options?):Promise<T>
Parameters
Returns
Promise<T>
EmailChannelAdapter
Properties channelMethods inbound()readonlychannel:"email"
inbound(Normalise onepayload):Promise<EmailChannelInbound|undefined>
email.received payload (the webhook’s data.payload).
The envelope’s id is the message id a redelivery repeats; the thread is
the conversation (email-<thread id>) when the envelope names it or the
message is found in the inbox by its id, else the sender’s (email-<sender>),
so a redelivery lands in the same conversation whatever the inbox holds
by then. The text is the platform’s reply_text, else the plain-text body
at text_body_url with its quoted tail dropped, else the message read
back from its thread. Nothing when the mail is not this adapter’s, cannot
be placed in an inbox, or has no text: an event says why. Throws
EmailInboundUnavailableError when a read it needed failed and may pass.
Parameters
Returns
Promise<EmailChannelInbound | undefined>
send()
send(Reply in thread.request):Promise<{providerRequestId:string; }>
content is an EmailReplyContent; the idempotency key goes with the request. providerRequestId is the API’s id of the reply, else reply:<idempotency key>.
Parameters
Returns
Promise<{ providerRequestId: string; }>
EmailChannelInbound
Properties channelcontentreadonlychannel:"email"
conversationIdreadonlycontent:EmailInboundContent
externalMessageIdreadonlyconversationId:string
receivedAtreadonlyexternalMessageId:string
readonlyreceivedAt:number
EmailInboundContent
EmailInboundContent = object
What the model is given of a mail: the new text, and where it came from and goes back to.
Properties
from
inboxIdreadonlyfrom:string
The inbox the mail arrived in; the reply goes out from it. messageIdreadonlyinboxId:string
The inbox message the reply answers; the platform threads and addresses it. subject?readonlymessageId:string
textreadonlyoptionalsubject?:string
The new text of the mail, its quoted history and signature dropped. threadId?readonlytext:string
toreadonlyoptionalthreadId?:string
readonlyto: readonlystring[]
EmailReplyContent
EmailReplyContent = object
A reply: the text, and the message it answers. The inbox is the adapter’s unless named.
Properties
inboxId?
messageIdreadonlyoptionalinboxId?:string
textreadonlymessageId:string
readonlytext:string
EmailChannelEvent
EmailChannelEvent =Something the adapter noticed while handling a mail: why one was left alone, what it read, what failed.Readonly<{type:EmailChannelEventType; } &Record<string,unknown>>
type says which; the other fields are
its details. Hosts log them.
EmailChannelEventType
EmailChannelEventType ="unrecognised payload"|"not this agent's inbox"|"not this agent's address"|"no inbox for the recipient"|"inbox list failed"|"payload"|"message not in inbox yet"|"inbox read failed"|"body url skipped"|"body redirect skipped"|"body fetch failed"|"thread read failed"|"no text"
EmailInboundUnavailableError
The mail could not be normalised now, for a reason that may pass: the API refused or did not answer a read it needed (the inbox list, the inbox, the body, the thread). The host should answer the webhook with an error so the platform delivers it again; a mail left alone for good is not this. Constructors Constructornew EmailInboundUnavailableError(Parametersmessage,options?):EmailInboundUnavailableError
Returns
EmailInboundUnavailableError
Properties
retryable
readonlyretryable:true=true
emailConversation()
emailConversation(The conversation an email thread is: one per thread, so a reply in the thread continues it; else one per sender. Parametersstring
Returns
string
stripQuotedEmail()
stripQuotedEmail(The new text of a reply, without the quoted history under it: everything from the first “On … wrote:” line or the first quoted (text):string|undefined
>) line on is dropped,
and so is a signature after a -- line. Conservative: a mail that does not
look quoted is returned whole.
Parameters
Returns
string | undefined
isEmailBodyHost()
isEmailBodyHost(Whether a body URL is on one of the allowed hosts (the host itself or a subdomain), over https. Parametersurl,hosts?):boolean
Returns
boolean
EMAIL_BODY_HOSTS
Where an offloaded mail body may be fetched from by default: Telnyx’s own hosts, never an address the payload could point anywhere. The value isconstEMAIL_BODY_HOSTS: readonlystring[]
["telnyx.com", "telnyxstorage.com"].
redactUrl()
redactUrl(A URL as it may be logged: origin and path only. A body link is often signed, and its query (or userinfo, or fragment) can grant access to the mail it points at. Parametersurl):string
Returns
string
forgetEmailInboxCache()
forgetEmailInboxCache(): void
Forget the cached inbox lists (tests, or after an inbox was made).
Returns
void