chat-adapter-outlook-email
v0.1.1
Published
Microsoft Outlook / M365 email adapter for Vercel Chat SDK via Microsoft Graph
Maintainers
Readme
chat-adapter-outlook-email
Microsoft Outlook / M365 email adapter for the Vercel Chat SDK. Treats email conversations as Chat SDK threads using Microsoft Graph change notifications for inbound and Graph mail APIs for outbound.
Supports both dedicated bot mailboxes and shared mailboxes.
Install
pnpm add chat-adapter-outlook-email chat @chat-adapter/sharedQuick Start
import { Chat } from "chat";
import { createOutlookEmailAdapter } from "chat-adapter-outlook-email";
const adapter = createOutlookEmailAdapter({
tenantId: process.env.OUTLOOK_TENANT_ID,
clientId: process.env.OUTLOOK_CLIENT_ID,
clientSecret: process.env.OUTLOOK_CLIENT_SECRET,
mailbox: process.env.OUTLOOK_MAILBOX,
notificationUrl: process.env.OUTLOOK_NOTIFICATION_URL,
clientState: process.env.OUTLOOK_CLIENT_STATE,
});
const chat = new Chat({
adapter,
async onMessage({ message, thread, reply }) {
// Echo the message back as a threaded reply
await reply(`You said: ${message.text}`);
},
});
// Mount the webhook handler on your HTTP server
// POST /api/webhooks/outlook-email → chat.handleWebhook(request)Configuration
Environment Variables
| Variable | Required | Description |
|---|---|---|
| OUTLOOK_TENANT_ID | Yes | Azure AD / Entra ID tenant ID |
| OUTLOOK_CLIENT_ID | Yes | Azure AD application (client) ID |
| OUTLOOK_CLIENT_SECRET | Yes | Azure AD client secret |
| OUTLOOK_MAILBOX | Yes | Mailbox to monitor (comma-separated for multiple) |
| OUTLOOK_NOTIFICATION_URL | Yes | Public HTTPS URL for Graph webhook notifications |
| OUTLOOK_CLIENT_STATE | Yes | Secret for webhook verification (max 128 chars) |
| OUTLOOK_BOT_NAME | No | Bot display name (defaults to "Bot") |
All configuration can also be passed directly via the OutlookEmailAdapterConfig object.
Azure AD App Registration
- Register an application in Azure AD / Entra ID
- Add application permissions:
Mail.ReadWrite+Mail.Send - Grant admin consent for the permissions
- Create a client secret
- (Recommended) Scope access to your bot mailbox using RBAC for Applications in Exchange Online to avoid tenant-wide mailbox access
Features
Receive Emails via Webhooks
Inbound emails are received via Microsoft Graph change notifications and delivered as normalized Chat SDK Message objects. The adapter handles subscription creation, renewal, and reconciliation automatically.
Reply to Email Threads
Replies are sent as properly threaded responses using Graph's createReply API:
async onMessage({ message, reply }) {
await reply("Thanks for your email! We'll get back to you shortly.");
}Send Emails Proactively
Start new outbound email threads using openDM:
const threadId = await chat.openDM("[email protected]");
await chat.postMessage(threadId, "Hello from the bot!");Markdown and Rich Content
Send formatted messages using markdown:
await reply({ markdown: "**Important:** Please review the attached document." });Or pass an mdast AST directly:
await reply({ ast: myMdastRoot });Attachments
Inbound attachments are mapped to Chat SDK Attachment objects with type detection (image, video, audio, file). Outbound files can be attached via the files property:
await reply({
markdown: "Here's the report you requested.",
files: [{ data: pdfBuffer, filename: "report.pdf", mimeType: "application/pdf" }],
});Fetch Message History
Retrieve the full conversation history for an email thread:
const { messages, nextCursor } = await chat.fetchMessages(threadId, { limit: 50 });Email Body Normalization
Inbound email bodies are automatically cleaned up:
- Quoted reply chains are stripped (Outlook, Gmail, Apple Mail formats)
- Signatures are removed (
--,Sent from my iPhone, etc.) - HTML is converted to plain text
- The original HTML is preserved in
message.rawfor handlers that need full fidelity
Shared Mailbox Support
Shared mailboxes work identically to dedicated mailboxes — just configure the shared mailbox address in OUTLOOK_MAILBOX. No additional code or permissions are needed (application permissions access shared mailboxes the same way via Graph API).
Unsupported Operations
These methods throw NotImplementedError as they have no email equivalent:
editMessage()— email cannot be edited after senddeleteMessage()— email cannot be recalled reliablyaddReaction()/removeReaction()— no email equivalentstartTyping()— no email equivalent
Loop Prevention
The adapter uses multiple layers to prevent reply loops:
- From-address check — messages from the bot's own mailbox are skipped
- Custom header — outbound messages include
X-Chat-SDK-Bot: true; inbound messages with this header are skipped - Auto-reply detection — OOF replies, read receipts, and Exchange-generated messages are filtered via
Auto-Submittedand related headers
License
MIT
