Skip to content

@memberjunction/communication-ms-graph

Microsoft Graph (Office 365 / Exchange Online) provider for the MemberJunction Communication Framework. This provider enables full mailbox operations — sending, receiving, searching, managing folders, attachments, drafts, and more — through the Microsoft Graph API with Azure AD application authentication.

graph TD
    subgraph msgraph["@memberjunction/communication-ms-graph"]
        MSP["MSGraphProvider"]
        AUTH["Auth Module\n(ClientSecretCredential)"]
        CFG["Config Module\n(Environment Variables)"]
        CRED["MSGraphCredentials"]
    end

    subgraph azure["Azure / Microsoft"]
        AAD["Azure AD\n(OAuth2 Client Credentials)"]
        GRAPH["Microsoft Graph API\n(/users/email/...)"]
        MAIL["Exchange Online\nMailbox"]
    end

    subgraph base["@memberjunction/communication-types"]
        BCP["BaseCommunicationProvider"]
    end

    BCP --> MSP
    MSP --> AUTH
    MSP --> CFG
    MSP --> CRED
    AUTH --> AAD
    MSP --> GRAPH
    GRAPH --> MAIL

    style msgraph fill:#2d6a9f,stroke:#1a4971,color:#fff
    style azure fill:#7c5295,stroke:#563a6b,color:#fff
    style base fill:#2d8659,stroke:#1a5c3a,color:#fff
Terminal window
npm install @memberjunction/communication-ms-graph

Set the following environment variables:

AZURE_TENANT_ID=your-azure-tenant-id
AZURE_CLIENT_ID=your-azure-app-client-id
AZURE_CLIENT_SECRET=your-azure-app-client-secret
AZURE_ACCOUNT_EMAIL=mailbox@yourdomain.com

Required Azure AD App Permissions (Application type)

Section titled “Required Azure AD App Permissions (Application type)”
PermissionOperations
Mail.SendSendSingleMessage, ForwardMessage, ReplyToMessage
Mail.ReadGetMessages, GetSingleMessage, SearchMessages, ListFolders, ListAttachments, DownloadAttachment
Mail.ReadWriteCreateDraft, DeleteMessage, MoveMessage, MarkAsRead, ArchiveMessage
User.Read.AllGetServiceAccount (user lookup, optional)

This provider supports all 14 operations defined in BaseCommunicationProvider:

OperationDescription
SendSingleMessageSend email via Graph API
GetMessagesRetrieve messages with filtering and header extraction
GetSingleMessageRetrieve a single message by ID
ForwardMessageForward email to new recipients
ReplyToMessageReply to an existing email thread
CreateDraftCreate a draft message in the mailbox
DeleteMessageMove to Deleted Items or permanently delete
MoveMessageMove message to a different mail folder
ListFoldersList mail folders with optional message counts
MarkAsReadMark messages as read or unread (batch)
ArchiveMessageMove message to Archive folder
SearchMessagesFull-text search with KQL syntax and date filtering
ListAttachmentsList attachments on a message
DownloadAttachmentDownload attachment content as base64/Buffer
import { CommunicationEngine } from '@memberjunction/communication-engine';
import { Message } from '@memberjunction/communication-types';
const engine = CommunicationEngine.Instance;
await engine.Config(false, contextUser);
const message = new Message();
message.From = 'user@yourdomain.com';
message.To = 'recipient@example.com';
message.Subject = 'Hello from MS Graph';
message.HTMLBody = '<h1>Hello</h1><p>Sent via Microsoft Graph.</p>';
message.ContextData = { saveToSentItems: true };
const result = await engine.SendSingleMessage(
'Microsoft Graph',
'Standard Email',
message
);

Override credentials on a per-request basis for multi-tenant scenarios:

import { MSGraphCredentials } from '@memberjunction/communication-ms-graph';
const result = await engine.SendSingleMessage(
'Microsoft Graph',
'Standard Email',
message,
undefined,
false,
{
tenantId: 'customer-tenant-id',
clientId: 'customer-app-id',
clientSecret: 'customer-secret',
accountEmail: 'user@customer.com'
} as MSGraphCredentials
);
const provider = engine.GetProvider('Microsoft Graph');
const result = await provider.GetMessages({
NumMessages: 10,
UnreadOnly: true,
IncludeHeaders: true,
ContextData: {
ReturnAsPlainText: true,
MarkAsRead: true
}
});
result.Messages.forEach(msg => {
console.log(`${msg.From}: ${msg.Subject}`);
console.log(`Thread: ${msg.ThreadID}`);
});

MS Graph supports KQL (Keyword Query Language) for search:

const result = await provider.SearchMessages({
Query: 'invoice',
FromDate: new Date('2025-01-01'),
MaxResults: 25,
FolderID: 'inbox-folder-id'
});
const result = await engine.CreateDraft(message, 'Microsoft Graph', contextUser);
if (result.Success) {
console.log(`Draft ID: ${result.DraftID}`);
}
// List top-level folders
const folders = await provider.ListFolders({ IncludeCounts: true });
folders.Folders.forEach(f => {
console.log(`${f.Name}: ${f.MessageCount} total, ${f.UnreadCount} unread`);
});
// List subfolders
const subfolders = await provider.ListFolders({
ParentFolderID: 'parent-folder-id',
IncludeCounts: true
});
// Move a message
await provider.MoveMessage({
MessageID: 'msg-id',
DestinationFolderID: 'folder-id'
});
// Archive a message
await provider.ArchiveMessage({ MessageID: 'msg-id' });
const attachments = await provider.ListAttachments({ MessageID: 'msg-id' });
for (const att of attachments.Attachments) {
const download = await provider.DownloadAttachment({
MessageID: 'msg-id',
AttachmentID: att.ID
});
// download.Content is a Buffer
// download.ContentBase64 is the raw base64 string
}

The provider caches Microsoft Graph Client instances per credential set for performance. Environment credential clients are shared across all calls; per-request credential clients are cached by tenantId:clientId.

Exchange Display NameSystemFolderType
Inboxinbox
Sent Itemssent
Draftsdrafts
Deleted Itemstrash
Junk Emailspam
Archivearchive
Other foldersother

When ReturnAsPlainText is set in ContextData, the provider uses the html-to-text library to convert HTML email bodies to plain text with 130-character word wrap.

PackagePurpose
@memberjunction/communication-typesBase provider class and type definitions
@memberjunction/coreLogging utilities
@memberjunction/globalRegisterClass decorator
@microsoft/microsoft-graph-clientMicrosoft Graph SDK
@azure/identityAzure AD ClientSecretCredential
html-to-textHTML to plain text conversion
Terminal window
npm run build # Compile TypeScript
npm run clean # Remove dist directory