> ## Documentation Index
> Fetch the complete documentation index at: https://docs.custral.com/llms.txt
> Use this file to discover all available pages before exploring further.

# email.sent

> A message from one of the workspace's connected mailboxes, in a thread that is a conversation.

Fires when a message sent from one of the workspace's connected mailboxes shows
up in a connected mailbox and its thread is a conversation in Custral. Mail sent
from Custral and mail sent from the mailbox's own mail app both count, because
Custral sees the sent copy either way.

## Payload

```json theme={null}
{
  "id": "whd_3Pv6nW8kD",
  "event": "email.sent",
  "createdAt": "2026-09-11T14:20:09.402Z",
  "data": {
    "messageId": "18f2d6b1c9e04a7d",
    "threadId": "18f2d1c04b7e9a23",
    "channelId": "chan_4Kp8wN",
    "conversationId": "conv_3Hq9rT",
    "from": "maya@acme.com",
    "fromName": "Maya Chen",
    "to": ["ada@ravennafoods.com"],
    "cc": [],
    "subject": "Re: Pricing for the Ravenna rollout",
    "receivedAt": "2026-09-11T14:20:05.000Z",
    "folder": "SENT"
  }
}
```

<ResponseField name="messageId" type="string" required>
  The mail provider's id for the message. Always present.
</ResponseField>

<ResponseField name="threadId" type="string">
  The mail provider's id for the thread.
</ResponseField>

<ResponseField name="channelId" type="string">
  The connected mailbox the copy turned up in.
</ResponseField>

<ResponseField name="conversationId" type="string">
  The conversation the thread belongs to. Present on every delivery.
</ResponseField>

<ResponseField name="from" type="string">
  The address the message was sent from: one of the workspace's connected
  mailboxes.
</ResponseField>

<ResponseField name="fromName" type="string">
  The sender's display name. **Omitted** when the message carries none.
</ResponseField>

<ResponseField name="to" type="string[]">
  The addresses the message was sent to.
</ResponseField>

<ResponseField name="cc" type="string[]">
  The addresses copied. An empty array when nobody was copied.
</ResponseField>

<ResponseField name="subject" type="string">
  The subject line. An empty string when the message has none.
</ResponseField>

<ResponseField name="receivedAt" type="string">
  The message's date, as an ISO 8601 timestamp. For mail your team sent, this
  is when it was sent.
</ResponseField>

<ResponseField name="folder" type="string">
  The provider's id for the first folder or label the message is filed under.
  **Omitted** when the provider lists none.
</ResponseField>

<ResponseField name="recordIds" type="string[]">
  Records the message is linked to. Mail from a connected mailbox does not carry
  them today, so this is omitted.
</ResponseField>

## When it fires

* **The sender is one of the workspace's connected mailboxes**, a teammate's
  included, whichever connected mailbox the copy turns up in.
* **The thread is a conversation.** A message in a thread that is already a
  conversation counts. A new outgoing thread counts when the **New mail
  handling** setting turns it into one, judged on its recipients, so mail sent
  only to teammates never counts.

## What sends nothing

* **A repeat of the same message.** Custral skips a message it has processed in
  the last five minutes, so a message that lands in several connected mailboxes,
  such as the sender's copy and a copied teammate's, is delivered once.
* **A message in a spam folder.** Mail the provider files as spam or junk sends
  no email event at all.
* **Replies from a forwarding address.** When a mailbox forwards its incoming
  mail to another address, a reply sent from that address is handled by the
  forwarding and usually sends nothing.

## Worth knowing

* **Opens and clicks are separate events**, and only for mail a workflow or a
  sequence sent: [`email.opened`](/dev/webhooks/events/email-opened) and
  [`email.clicked`](/dev/webhooks/events/email-clicked).
* **No body.** Read the message itself from the conversation through the
  [Conversations API](/dev/api-reference/conversations).
* **Ids belong to one mailbox.** Each connected mailbox has its own `messageId`
  and `threadId` for the same mail. Key on `conversationId` to follow a
  conversation.

## Example

```ts theme={null}
custral.on("email.sent", async (event) => {
  const {from, to, subject, conversationId} = event.data;

  await activity.logOutbound({from, to, subject, conversationId});
});
```


## Related topics

- [Email](/dev/webhooks/events/email.md)
- [email.received](/dev/webhooks/events/email-received.md)
- [email.clicked](/dev/webhooks/events/email-clicked.md)
- [email.opened](/dev/webhooks/events/email-opened.md)
- [email.replied](/dev/webhooks/events/email-replied.md)
