Skip to main content

Programmatic Graph workflows

A workflow combines dependent Graph operations in one process. Complete CLI setup first. Use designated mailboxes because these workflows send and modify real messages.

Send, wait, and move​

Run from Architecture/GraphSyncExperimenter/cli-graph/:

bun run workflow:send-wait-move -- \
--sender-user-id sender@example.com \
--recipient-user-id recipient@example.com \
--recipient-address recipient@example.com \
--target-folder-name "Graph workflow target" \
--timeout-ms 120000

The workflow sends a unique message and waits for the recipient copy. It then moves that copy to the target folder. A timeout does not prove that sending failed. Check Sent before another send.

Mark read and add a category​

bun run workflow:mark-read-add-label -- \
--user-id person@example.com \
--immutable-email-id IMMUTABLE_ID \
--label-name "Graph Tested"

The message must belong to the selected mailbox. Inspect returned JSON and the process exit code. See outputs.

Typed references​

Use an explicit folder ID when available:

await toolkit.email.moveEmail(
userId,
immutableEmailId,
{ id: "AAMkAG..." },
);

A unique exact folder name also works:

await toolkit.email.moveEmail(
userId,
immutableEmailId,
{ name: "Graph Tests" },
);

Categories accept their unique names:

await toolkit.email.addLabel(
userId,
immutableEmailId,
{ name: "Graph Tested" },
);

Name matching ignores case and requires one exact result. An ambiguous name needs an ID.

Cross-mailbox identity​

Never use the sender copy's immutable ID for the recipient mailbox. Correlate with internetMessageId, then use the recipient result's emailId. Set a finite wait timeout, such as --timeout-ms 120000.

See CLI wait options for polling behavior. The project's workflows/README.md describes the bundled workflows. Permanent deletion requires an explicit --confirm in the relevant CLI command. It is not a dry-run option.