Parlel › Docs › Outlook Outlook
Lightweight, dependency-free Microsoft Graph mail fake for local tests with @microsoft/microsoft-graph-client.
Defaults
Setting Value Service name outlookDefault port 4620Protocol HTTP, Microsoft Graph REST-style JSON Healthcheck GET /_parlel/healthReset POST /_parlel/resetBase URL http://127.0.0.1:4620/v1.0
Quick Start
import { OutlookServer } from "./services/outlook/src/server.js";
import { Client } from "@microsoft/microsoft-graph-client";
const server = new OutlookServer(4620);
await server.start();
const client = Client.init({
baseUrl: "http://127.0.0.1:4620/v1.0",
authProvider: (done) => done(null, "local-token"),
});
await client.api("/me/sendMail").post({
message: {
subject: "Hello from parlel",
body: { contentType: "text", content: "Local only" },
toRecipients: [{ emailAddress: { address: "agent@example.com" } }],
},
saveToSentItems: true,
});
const messages = await client.api("/me/mailFolders/sentitems/messages").get();
await server.stop();
Implemented Operations
Emulator
Method Endpoint Notes GET/_parlel/healthReturns service status and object counts. POST/_parlel/resetClears ephemeral state and restores default folders/categories. GET/, /v1.0, /betaLightweight metadata response.
Users and Settings
Method Endpoint Notes GET/v1.0/meReturns the current user. GET/v1.0/users/{userId}Returns the requested local user. GET/v1.0/me/mailboxSettingsReturns mailbox settings. PATCH/v1.0/me/mailboxSettingsMerges mailbox setting changes.
Mail Folders
Method Endpoint Notes GET/v1.0/me/mailFoldersLists top-level folders. Supports $top, $skip, $count, $filter, $search, $orderby, $select. POST/v1.0/me/mailFoldersCreates a top-level folder. GET/v1.0/me/mailFolders/{id}Gets a folder. PATCH/v1.0/me/mailFolders/{id}Updates displayName. DELETE/v1.0/me/mailFolders/{id}Deletes non-default folders. GET/v1.0/me/mailFolders/{id}/childFoldersLists child folders. POST/v1.0/me/mailFolders/{id}/childFoldersCreates a child folder. GET/v1.0/me/mailFolders/{id}/childFolders/{childId}Gets a child folder. PATCH/v1.0/me/mailFolders/{id}/childFolders/{childId}Updates a child folder. DELETE/v1.0/me/mailFolders/{id}/childFolders/{childId}Deletes a child folder.
Default folders are inbox, drafts, sentitems, deleteditems, junkemail, archive, and outbox.
Messages and Drafts
Method Endpoint Notes GET/v1.0/me/messagesLists messages. Supports $top, $skip, $count, $filter, $search, $orderby, $select. POST/v1.0/me/messagesCreates a draft message by default. GET/v1.0/me/messages/$countReturns a plain-text count. GET/v1.0/me/messages/deltaReturns current messages plus @odata.deltaLink. GET/v1.0/me/messages/{id}Gets a message. Supports $select and $expand=attachments. PATCH/v1.0/me/messages/{id}Updates common mutable message fields. DELETE/v1.0/me/messages/{id}Soft-deletes a message from visible results. GET/v1.0/me/mailFolders/{folderId}/messagesLists messages in a folder. POST/v1.0/me/mailFolders/{folderId}/messagesCreates a draft message in a folder. GET/v1.0/me/mailFolders/{folderId}/messages/deltaFolder-scoped delta list.
Message Actions
Method Endpoint Notes POST/v1.0/me/sendMailSends a new message and returns 202. Honors saveToSentItems: false by hiding the stored sent copy. POST/v1.0/me/messages/{id}/sendSends a draft and moves it to sentitems. POST/v1.0/me/messages/{id}/replyCreates a sent reply and returns 202. POST/v1.0/me/messages/{id}/replyAllCreates a sent reply-all and returns 202. POST/v1.0/me/messages/{id}/forwardCreates a sent forward and returns 202. POST/v1.0/me/messages/{id}/createReplyCreates and returns a reply draft. POST/v1.0/me/messages/{id}/createReplyAllCreates and returns a reply-all draft. POST/v1.0/me/messages/{id}/createForwardCreates and returns a forward draft. POST/v1.0/me/messages/{id}/moveMoves a message to destinationId and returns it. POST/v1.0/me/messages/{id}/copyCopies a message to destinationId and returns the copy.
Attachments
Method Endpoint Notes GET/v1.0/me/messages/{id}/attachmentsLists file attachments. POST/v1.0/me/messages/{id}/attachmentsCreates a #microsoft.graph.fileAttachment. GET/v1.0/me/messages/{id}/attachments/{attachmentId}Gets attachment metadata and contentBytes. GET/v1.0/me/messages/{id}/attachments/{attachmentId}/$valueReturns raw attachment bytes. DELETE/v1.0/me/messages/{id}/attachments/{attachmentId}Deletes an attachment.
Message Rules
Method Endpoint Notes GET/v1.0/me/mailFolders/{folderId}/messageRulesLists message rules for a folder. POST/v1.0/me/mailFolders/{folderId}/messageRulesCreates a message rule. GET/v1.0/me/mailFolders/{folderId}/messageRules/{ruleId}Gets a message rule. PATCH/v1.0/me/mailFolders/{folderId}/messageRules/{ruleId}Updates a message rule. DELETE/v1.0/me/mailFolders/{folderId}/messageRules/{ruleId}Deletes a message rule.
Outlook Categories
Method Endpoint Notes GET/v1.0/me/outlook/masterCategoriesLists categories. POST/v1.0/me/outlook/masterCategoriesCreates a category. GET/v1.0/me/outlook/masterCategories/{id}Gets a category. PATCH/v1.0/me/outlook/masterCategories/{id}Updates a category. DELETE/v1.0/me/outlook/masterCategories/{id}Deletes a category.
Subscriptions and Batch
Method Endpoint Notes GET/v1.0/subscriptionsLists subscriptions. POST/v1.0/subscriptionsCreates a subscription. Requires changeType, notificationUrl, and resource. GET/v1.0/subscriptions/{id}Gets a subscription. PATCH/v1.0/subscriptions/{id}Updates a subscription. DELETE/v1.0/subscriptions/{id}Deletes a subscription. POST/v1.0/$batchExecutes JSON batch requests against the in-process router.
Surface coverage
This emulator faithfully replicates the API surface most application code and agents exercise. Anything below the supported lines is either an intentional design choice for a fast, zero-cost local emulator (✓ By design) or a candidate for a future release (⟳ Roadmap) — never a silent inaccuracy.
Legend: ✅ fully supported · ◐ accepted (stored, not strictly enforced) · ✓ by design · ⟳ on the roadmap.
Feature Status Notes @microsoft/microsoft-graph-client REST callsSupported Use Client.init({ baseUrl, authProvider }). Auth tokens are accepted but ignored. Microsoft Graph v1.0 and beta prefixes Supported Both route to the same fake implementation. In-memory mail folders, messages, drafts, actions, attachments Supported State is ephemeral and resettable. OData paging/filter/search/order/select/count Supported Lightweight common subset for local tests. Delta links Supported Returns current state plus a synthetic @odata.deltaLink. Webhook subscription CRUD Supported Stored locally. No outbound HTTP notifications are sent. JSON batch Supported Routes batch items in process. Authentication, authorization, tenants, permissions Intentionally unsupported Tokens are ignored to keep local tests zero-config. Real Exchange delivery, spam filtering, transport rules Intentionally unsupported No side effects leave the process. Calendar, contacts, OneDrive, Teams, non-mail Graph resources Intentionally unsupported This fake is scoped to Graph mail. MIME upload sessions and large attachment upload sessions Intentionally unsupported Use normal file attachment contentBytes.
Error Shapes
Errors follow the Microsoft Graph JSON shape:
{
"error": {
"code": "ErrorItemNotFound",
"message": "Message not found",
"innerError": {
"date": "2026-06-11T00:00:00.000Z",
"request-id": "req_...",
"client-request-id": "optional-client-id"
}
}
}
Common returned codes:
HTTP Graph code When 400ErrorInvalidRequestMissing required fields, invalid JSON, invalid default-folder deletion. 404ErrorItemNotFoundMissing users, folders, messages, attachments, rules, categories, or subscriptions. 404Request_ResourceNotFoundUnknown route. 405Request_BadRequestUnsupported HTTP method for an implemented route. 500InternalServerErrorUnexpected server errors.
<!-- parlel:testenv:start -->
Configuration — test.env
Copy these into your test.env (used by the bridge sidecar flow). Tokens are Parlel's seeded test credentials — any non-empty value is accepted by the emulator, so you rarely need to change them. Swap in real credentials only when pointing at the live service in prod.env.
OUTLOOK_EMULATOR_HOST=http://parlel-bridge:4620
MICROSOFT_GRAPH_BASE_URL=http://parlel-bridge:4620/v1.0
AZURE_TENANT_ID=parlel
AZURE_CLIENT_ID=parlel
AZURE_CLIENT_SECRET=parlel
<!-- parlel:testenv:end -->
Related references