msgraph-shared-mailbox
v1.2.0
Published
Email Node.js library compatible with Microsoft Graph API
Maintainers
Readme
msgraph-shared-mailbox
Email library for Node.js that sends mail from an Exchange Online shared mailbox via Microsoft Graph. It supports text or HTML bodies, small and large attachments (buffer, local file path, or remote URL), and fetching mail by ID.
Features
- Send email from a shared mailbox using Microsoft Graph.
- Text or HTML body with
to,cc,bccrecipients. - Attachments from memory (
content), local path (path), or URL (href). - Automatic large file upload via Graph Upload Session when over threshold.
- Recipient parsing for strings or arrays; deduplicates comma/semicolon-separated addresses.
- Fetch message by ID with optional attachments.
- Minimal logging hook for error reporting.
Installation
pnpm add msgraph-shared-mailbox
# or
npm install msgraph-shared-mailboxRequires Node.js 18+.
Prerequisites
- Azure AD App Registration with a Client Secret (Client Credentials flow).
- Application permissions granted and consented:
Mail.Sendfor sending emails.Mail.Readif you will read messages or attachments.
- A valid shared mailbox address in your tenant, e.g.
[email protected].
Quickstart
import { MailClient } from 'msgraph-shared-mailbox'
const mailClient = new MailClient({
tenantId: process.env.TENANT_ID!,
clientId: process.env.CLIENT_ID!,
clientSecret: process.env.CLIENT_SECRET!,
sharedMailbox: process.env.SHARED_MAILBOX!,
// Large upload settings (defaults shown)
attachmentUploadOptions: {
largeFileThreshold: 3 * 1024 * 1024, // 3MB
chunkSize: 320 * 1024 // 320KB (must be 320KB multiple)
}
})
await mailClient.sendMail({
subject: 'Hello from msgraph-shared-mailbox',
to: '[email protected]', // string with comma/semicolon or an array
text: 'This is a text body. You can also use HTML.'
})Singleton alternative:
// Initialize once at app startup
import { MailClient } from 'msgraph-shared-mailbox'
export const mailClient = MailClient.getInstance({
tenantId: process.env.TENANT_ID!,
clientId: process.env.CLIENT_ID!,
clientSecret: process.env.CLIENT_SECRET!,
sharedMailbox: process.env.SHARED_MAILBOX!,
attachmentUploadOptions: {
largeFileThreshold: 3 * 1024 * 1024,
chunkSize: 320 * 1024
}
})
// Use anywhere else
await mailClient.sendMail({ subject: '...', to: '[email protected]', text: '...' })Attachments
Provide attachments via any of the following fields:
content:Buffer | stringkept in memory (small files)path: local file pathhref: remote file URL (http/https)
Example:
await mailClient.sendMail({
subject: 'Email with attachments',
to: '[email protected]',
text: 'Attachments from content, path and href',
attachments: [
{ filename: 'note.txt', content: Buffer.from('Hello attachment content') },
{ filename: 'sample.txt', path: '/absolute/path/to/sample.txt' },
{ filename: 'bytes.bin', href: 'https://httpbin.org/bytes/1024' }
]
})Limits:
- Single attachment size must be ≤ 150MB (Graph upload session limit).
- Attachments larger than
largeFileThresholduse an upload session withchunkSizethat must be a multiple of 320KB.
Fetch a Message by ID
const message = await mailClient.getMailById('<MESSAGE_ID>', {
includeAttachments: true
// choose fields if needed
// select: ['id', 'subject']
})You can also fetch by the RFC822 Internet Message ID (internetMessageId), which typically includes angle brackets like '<...@...>':
// Option A: auto-detection when the ID looks like <...@...>
const msg1 = await mailClient.getMailById('<[email protected]>', {
includeAttachments: true
})
// Option B: explicitly specify idType
const msg2 = await mailClient.getMailById('<[email protected]>', {
idType: 'internetMessageId',
includeAttachments: true,
select: ['id', 'subject']
})API
MailClient(options: CredentialOptions)
Options:
tenantId: Azure AD tenant ID.clientId: App registration (client) ID.clientSecret: Client secret for the app.sharedMailbox: Shared mailbox email address.attachmentUploadOptions?: (optional) Large upload settings.largeFileThreshold?: number (default 3MB).chunkSize?: number (default 320KB, must be 320KB multiple).
logger?:{ error?: (...args: any[]) => void }(optional).
Singleton Mode
Use MailClient.getInstance(options) to create a process-wide singleton:
const mc = MailClient.getInstance({
tenantId: '...',
clientId: '...',
clientSecret: '...',
sharedMailbox: '...',
attachmentUploadOptions: { largeFileThreshold: 3 * 1024 * 1024, chunkSize: 320 * 1024 }
})Notes:
- Only the first call initializes the instance; later calls return the same instance and ignore new options.
- Prefer singleton for single-tenant apps. If you need different credentials/mailboxes per request, create separate
new MailClient(options)instances instead.
sendMail(mail: MailOptions): Promise
Sends and returns the new message ID.
Return value details:
- Returns the Graph message
idas astringandinternetMessageIdas astring. - Implementation: creates a draft (
POST /users/{mailbox}/messages), uploads attachments, then sends (POST /users/{mailbox}/messages/{id}/send). The returnedidis the sent message ID. - Use this
idwithgetMailById(id, { includeAttachments: true })to retrieve message details or attachments. - If you need the RFC822
internetMessageId, query the message and readinternetMessageId, or later fetch by it usinggetMailById('<...@...>', { idType: 'internetMessageId' }).
MailOptions:
subject: stringto: string | string[] (supports comma/semicolon; deduplicated)cc?: string | string[]bcc?: string | string[]- One of:
{ text: string }{ html: string }
attachments?: Array of{ filename?, content?, path?, href? }
getMailById(id: string, options?: { select?: string[]; includeAttachments?: boolean }): Promise
Fetches a message by ID. When includeAttachments is true, attachments are queried and merged into the result.
Run the Examples
pnpm i
# Set required environment variables
export TENANT_ID=...
export CLIENT_ID=...
export CLIENT_SECRET=...
export [email protected]
# Basic send
pnpm ts-node examples/basic-send.ts
# Send with attachments
pnpm ts-node examples/attachments.ts
# Fetch a message by ID
export MESSAGE_ID=...
pnpm ts-node examples/get-mail-by-id.tsTroubleshooting
insufficient privileges: ensure the app hasMail.Send(andMail.Readif reading) application permissions with admin consent.- Shared mailbox not found: verify
sharedMailboxaddress and that the mailbox exists in your tenant. - Large attachments failing: set
chunkSizeto a multiple of 320KB and keep each attachment ≤ 150MB. - Rate limits (HTTP 429): consider retry/backoff; this library does not implement automatic retries.
License
MIT © Chakhsu.Lau
