Skip to content

@memberjunction/communication-gmail

Gmail / Google Workspace provider for the MemberJunction Communication Framework. This provider enables full mailbox operations — sending, receiving, searching, managing labels, attachments, drafts, and more — through the Gmail API with OAuth2 authentication.

graph TD
    subgraph gmail["@memberjunction/communication-gmail"]
        GP["GmailProvider"]
        AUTH["Auth Module\n(OAuth2 Client)"]
        CFG["Config Module\n(Environment Variables)"]
        CRED["GmailCredentials"]
    end

    subgraph google["Google APIs"]
        OAUTH["Google OAuth2"]
        GAPI["Gmail API v1\n(/users/me/...)"]
        MAILBOX["Gmail Mailbox"]
    end

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

    BCP --> GP
    GP --> AUTH
    GP --> CFG
    GP --> CRED
    AUTH --> OAUTH
    GP --> GAPI
    GAPI --> MAILBOX

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

Set the following environment variables:

GMAIL_CLIENT_ID=your-oauth2-client-id
GMAIL_CLIENT_SECRET=your-oauth2-client-secret
GMAIL_REDIRECT_URI=your-redirect-uri
GMAIL_REFRESH_TOKEN=your-refresh-token
GMAIL_SERVICE_ACCOUNT_EMAIL=noreply@yourdomain.com # optional default sender
  • https://www.googleapis.com/auth/gmail.send
  • https://www.googleapis.com/auth/gmail.readonly
  • https://www.googleapis.com/auth/gmail.modify
  • https://www.googleapis.com/auth/gmail.compose
  1. Go to the Google Cloud Console
  2. Create or select a project and enable the Gmail API
  3. Create OAuth 2.0 Client ID credentials
  4. Configure the OAuth consent screen
  5. Use the OAuth2 flow to obtain a refresh token with the required scopes

This provider supports all 14 operations defined in BaseCommunicationProvider:

OperationGmail Implementation
SendSingleMessageSend via users.messages.send
GetMessagesList and fetch with Gmail search query support
GetSingleMessageFetch single message by ID
ForwardMessageReconstruct and send as RFC 822 attachment
ReplyToMessageSend in same thread via threadId
CreateDraftCreate via users.drafts.create
DeleteMessageTrash or permanently delete
MoveMessageAdd/remove labels via users.messages.modify
ListFoldersList labels with optional message/unread counts
MarkAsReadAdd/remove UNREAD label (batch)
ArchiveMessageRemove INBOX label
SearchMessagesGmail query syntax with date filters
ListAttachmentsParse message parts recursively for attachments
DownloadAttachmentDownload via users.messages.attachments.get
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 = 'sender@gmail.com';
message.To = 'recipient@example.com';
message.Subject = 'Hello from Gmail';
message.HTMLBody = '<h1>Hello</h1>';
message.CCRecipients = ['cc@example.com'];
const result = await engine.SendSingleMessage('Gmail', 'Email', message);

Override credentials for multi-user scenarios:

import { GmailCredentials } from '@memberjunction/communication-gmail';
const result = await provider.SendSingleMessage(processedMessage, {
clientId: 'other-client-id',
clientSecret: 'other-secret',
redirectUri: 'other-redirect',
refreshToken: 'user-specific-refresh-token'
} as GmailCredentials);
const provider = engine.GetProvider('Gmail');
const result = await provider.GetMessages({
NumMessages: 10,
UnreadOnly: true,
ContextData: {
query: 'from:important@example.com', // Gmail search syntax
MarkAsRead: true
}
});
result.Messages.forEach(msg => {
console.log(`${msg.From}: ${msg.Subject}`);
console.log(`Thread: ${msg.ThreadID}`);
});
const result = await provider.CreateDraft({ Message: processedMessage });
if (result.Success) {
console.log(`Draft ID: ${result.DraftID}`);
// Draft appears in Gmail drafts folder
}
const result = await provider.SearchMessages({
Query: 'has:attachment',
FromDate: new Date('2025-01-01'),
ToDate: new Date('2025-06-01'),
FolderID: 'INBOX', // Gmail label ID
MaxResults: 50
});
const folders = await provider.ListFolders({ IncludeCounts: true });
folders.Folders.forEach(f => {
console.log(`${f.Name} (${f.ID}): ${f.MessageCount} messages`);
console.log(` System: ${f.IsSystemFolder}, Type: ${f.SystemFolderType}`);
});
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 base64 string
// download.Filename, download.ContentType available
}

Gmail uses labels instead of traditional folders. The provider maps system labels to standard folder types:

Gmail LabelSystemFolderType
INBOXinbox
SENTsent
DRAFTdrafts
TRASHtrash
SPAMspam
User labelsundefined

The provider caches Gmail API client instances for performance. Environment credential clients are shared across all calls; per-request credential clients are cached by a key derived from clientId and refreshToken.

  1. Store refresh tokens securely and never commit them to version control
  2. Request only the minimum required OAuth2 scopes
  3. Use secure methods to manage environment variables in production
  4. Regularly rotate client secrets and monitor API usage
PackagePurpose
@memberjunction/communication-typesBase provider class and type definitions
@memberjunction/coreLogging utilities
@memberjunction/globalRegisterClass decorator
googleapisGoogle APIs Node.js client
dotenvEnvironment variable loading
env-varEnvironment variable validation
Terminal window
npm run build # Compile TypeScript
npm run clean # Remove dist directory