useDocyrusEmailComposer
Wire an `<EmailComposer />` to the Docyrus messaging API — loads sender accounts, lets the user pick a From address, and ships emails through `/v1/messaging/email/accounts/{id}/send`.
Installation
pnpm dlx @docyrus/cli add @docyrus/hooks-use-docyrus-email-composerpnpm add @docyrus/api-client @tanstack/react-queryThe hook needs an authenticated RestApiClient from @docyrus/api-client and a QueryClientProvider from @tanstack/react-query somewhere above your component tree. The access token must carry the Messaging.Email.Send scope — otherwise both the list-accounts and send calls return 403 insufficient_scope.
Overview
useDocyrusEmailComposer is the Docyrus-backed companion to EmailComposer. It does three things:
- Loads sender accounts —
GET /v1/messaging/email/accountsreturns both shared tenant accounts (tenant_email_configuration) and the caller's own connected OAuth mailboxes (Microsoft / Google). - Manages composer state —
to,cc,bcc,subject,body, plus the currently selected account id. State persists across re-renders and resets after a successful send (toggle viaresetOnSendSuccess). - Sends through the picked account —
POST /v1/messaging/email/accounts/{accountId}/sendreturns{ messageId, provider, accepted, rejected }. Per-call overrides let you setsendAsUser, storage-backedattachments, orreplyTowithout touching the composer state.
The first user-accessible account is auto-selected once the list resolves, so consumers don't have to wait for the user to pick before the composer becomes interactive.
Usage
Default integration
'use client';
import { useDocyrusAuth } from '@docyrus/signin';
import { EmailComposer } from '@docyrus/ui/components/email-composer';
import {
useDocyrusEmailComposer
} from '@docyrus/ui/library/hooks/use-docyrus-email-composer';
export function SendEmailDialog({ onClose }: { onClose: () => void }) {
const { client } = useDocyrusAuth();
if (!client) return null;
const composer = useDocyrusEmailComposer({
client,
initialTo: ['customer@example.com'],
initialSubject: 'Following up on your order'
});
return (
<EmailComposer
{...composer.composerProps}
onDiscard={onClose} />
);
}composerProps spreads the wiring for the From dropdown, recipient fields, subject, body, and the onSend handler. The composer's built-in Send button fires the hook's mutation; no glue required.
Sending with sendAsUser
For tenant accounts that allow it, sendAsUser: true overrides the From name/address with the authenticated user's identity at the API layer (subject to each account's allowOverrideName / allowOverrideEmail flags).
const composer = useDocyrusEmailComposer({
client,
sendAsUser: true // forwarded with every send call
});Or override it per call:
await composer.send({ sendAsUser: true });Storage-backed attachments
The composer's local EmailAttachment carries { name, size } only — it cannot be transmitted as-is, because the send endpoint expects files that already live in Docyrus storage. Upload first, then hand the storage path(s) to send():
await composer.send({
attachments: [
{ filePath: 'tenant-files/invoices/inv-1234.pdf', fileName: 'invoice.pdf', mimeType: 'application/pdf' }
]
});Reading the response
lastSendResult carries the latest server response so you can surface rejected recipients:
{composer.lastSendResult?.rejected.length > 0 && (
<p>The provider rejected: {composer.lastSendResult.rejected.join(', ')}</p>
)}Account selection
The dropdown surfaces every account returned by the API:
| Account kind | Source | Behavior |
|---|---|---|
tenant | Shared tenant configuration (tenant_email_configuration) | Send From is the configured senderName / senderEmail. sendAsUser may override these if allowOverride* is set. |
user | The caller's connected OAuth mailbox (tenant_connection_user) | Always sends as the user; sendAsUser is ignored by the server. |
Entries with isUserAccessible: false are rendered disabled in the dropdown — they exist in the tenant configuration but the current user can't send through them.
The hook auto-selects the first isUserAccessible: true account on first load. Override via initialAccountId or by calling setSelectedAccountId(id).
API Reference
useDocyrusEmailComposer(options)
| Option | Type | Default | Description |
|---|---|---|---|
client | RestApiClient | — | Authenticated Docyrus API client. |
initialTo | string[] | [] | Initial To recipients. |
initialCc | string[] | [] | Initial Cc recipients. |
initialBcc | string[] | [] | Initial Bcc recipients. |
initialReplyTo | string[] | [] | Initial Reply-To addresses (forwarded with every send). |
initialSubject | string | '' | Initial subject. |
initialBody | string | '' | Initial body HTML. |
initialAccountId | string | — | Preselect a specific account id. When omitted, the hook picks the first isUserAccessible: true account once the list resolves. |
resetOnSendSuccess | boolean | true | Clear to / cc / bcc / subject / body / attachments after a successful send. Disable to keep the composer populated for a follow-up send. |
enabled | boolean | true | Toggles the GET /v1/messaging/email/accounts query. |
sendAsUser | boolean | — | Default forwarded as sendAsUser on every send unless explicitly overridden. |
listAccountsEndpoint | string | /v1/messaging/email/accounts | Override the list endpoint. |
sendEndpoint | string | /v1/messaging/email/accounts/{accountId}/send | Override the send endpoint. {accountId} is replaced with the selected id. |
mentions | boolean | true | Toggles the GET /v1/users query that powers the body editor's @ mention autocomplete. /v1/users has no server-side search, so the list is fetched once (limit 1000, 5-minute stale time) and filtered client-side. |
mentionUsers | EmailComposerMentionUser[] | — | Explicit mention users. When provided, the /v1/users fetch is skipped. |
listUsersEndpoint | string | /v1/users | Override the mention users list endpoint. |
slashCommands | EmailComposerSlashCommand[] | — | Developer-defined / slash commands forwarded to the composer body editor. Pure passthrough — no fetching. See the composer's Slash Commands section for the command API. |
Return value
| Property | Type | Description |
|---|---|---|
composerProps | Pick<EmailComposerProps, ...> | Ready-to-spread props for <EmailComposer />. Wires accounts, selected account, all recipient/subject/body fields, mentionUsers, slashCommands, onSend, and sending. |
accounts | DocyrusEmailAccount[] | Raw account DTOs (includes provider / override metadata). |
selectedAccount | DocyrusEmailAccount | null | Currently selected account. |
setSelectedAccountId | (accountId: string) => void | Programmatically change the selection. |
isLoadingAccounts | boolean | First-fetch loading state for the accounts query. |
accountsError | Error | null | Last error from the accounts query (e.g. insufficient_scope). |
refetchAccounts | () => Promise<unknown> | Invalidate and refetch the accounts cache. |
mentionUsers | EmailComposerMentionUser[] | Users offered by the body editor's @ mention autocomplete (from mentionUsers option or the /v1/users fetch; empty when mentions: false). |
to / setTo | string[] / (next) => void | Direct access to the To state. |
cc / setCc | string[] / (next) => void | Direct access to the Cc state. |
bcc / setBcc | string[] / (next) => void | Direct access to the Bcc state. |
replyTo / setReplyTo | string[] / (next) => void | Direct access to the Reply-To state. |
subject / setSubject | string / (next) => void | Direct access to the subject. |
body / setBody | string / (next) => void | Direct access to the HTML body. |
attachments / setAttachments | EmailAttachment[] / (next) => void | Local attachment metadata. Not sent automatically — the send endpoint expects storage paths. |
send | (overrides?) => Promise<DocyrusEmailSendResult> | Trigger a send. Resolves with { messageId, provider, accepted, rejected }. |
isSending | boolean | Mutation in-flight state. |
sendError | Error | null | Last send error. |
lastSendResult | DocyrusEmailSendResult | null | Last successful send response — surface rejected recipients here. |
reset | () => void | Clear all field state back to the initial* values. |
send(overrides?)
Every field is optional — anything omitted falls back to current composer state.
| Field | Type | Default | Description |
|---|---|---|---|
to | string[] | state.to | Override To recipients. |
cc | string[] | state.cc | Override Cc recipients. |
bcc | string[] | state.bcc | Override Bcc recipients. |
replyTo | string[] | state.replyTo | Override Reply-To addresses. |
subject | string | state.subject | Override subject. |
body | string | state.body | Override HTML body. |
sendAsUser | boolean | options.sendAsUser | Override the sendAsUser flag. Honored only on tenant accounts with allowOverride* set. |
attachments | DocyrusEmailAttachment[] | — | Storage-backed attachments ({ filePath, fileName?, mimeType? }). |
accountId | string | selectedAccountId | Send through a specific account, bypassing the dropdown selection. |
Type Exports
| Type | Description |
|---|---|
UseDocyrusEmailComposerOptions | Hook option shape. |
UseDocyrusEmailComposerResult | Hook return shape. |
DocyrusEmailAccount | Account DTO returned by the list endpoint — extends EmailComposerAccount with provider / override metadata. |
DocyrusEmailAttachment | { filePath; fileName?; mimeType? } — payload shape for the send endpoint. |
DocyrusEmailSendOverrides | Optional overrides accepted by send(...). |
DocyrusEmailSendResult | { messageId; provider; accepted[]; rejected[] }. |
DocyrusEmailProvider | 'aws' | 'smtp' | 'mailgun' | 'resend' | 'microsoft-graph' | 'gmail'. |
Error handling
accountsError and sendError surface the underlying API failures verbatim. Common ones:
| Status | When | What to do |
|---|---|---|
401 | Missing/invalid access token. | Re-authenticate via @docyrus/signin. |
403 insufficient_scope | The access token doesn't include Messaging.Email.Send. | Add the scope to the OAuth2 client config, re-authorize. |
403 (accessible flag) | Selected account has isUserAccessible: false. | Disable the option in the dropdown (already done by default). |
404 | The chosen accountId doesn't exist. | Re-fetch the account list. |
400 | Validation failure (invalid email, missing subject/body, attachment limits). | Surface from sendError.message. |
useDocyrusDummyDataGeneratorWizard
One-call wiring of a Docyrus data source to the DummyDataGenerator — handles field-aware strategies, deterministic generation, preview, and batch insert in a single guided flow.
useDocyrusFieldComponent
Resolve the right UI component (form input, value renderer, data-grid cell, editable value, or TanStack column def builder) for any Docyrus data source field type.