Repository files navigation

Microsoft365-4D

Delphi VersionPlatformLicense

Pure Delphi library for Microsoft Graph API integration. Provides OAuth2 authentication with PKCE and typed clients for Mail, Calendar, Contacts, and SharePoint. No external dependencies beyond the Delphi RTL.

Table of Contents

Features

  • OAuth2 + PKCE authentication flow for Microsoft identity platform
  • Mail -search, read, draft, send, delete, move messages, list folders, attachments
  • Calendar -list, create, update, delete events, check schedule availability
  • Contacts -search, create, update, delete contacts
  • SharePoint -browse sites, list/search drive items, get file content
  • Zero dependencies -uses only System.Net.HttpClient (Delphi RTL)
  • Pluggable logging -TLogProc callback, no global logger
  • Shared HTTP client -all Graph clients can share a single TGraphHttpClient
  • Shared mailbox support -access shared/delegated mailboxes via MailboxAddress property
  • Typed responses -all API calls return strongly-typed records (TMailMessage, TCalendarEvent, etc.)
  • Interface-based -all clients implement interfaces (IMailClient, ICalendarClient, etc.) for dependency injection

Requirements

  • Delphi 11 Alexandria or later (RAD Studio 11.x+)
  • Azure AD App Registration with appropriate API permissions

Installation

Using as a Library

Add the Source/OAuth2 and Source/Graph directories to your project's search path:

Source\OAuth2;Source\Graph

Then add the units you need to your uses clause:

uses
MSGraph.OAuth2.Types,
MSGraph.OAuth2.PKCE,
MSGraph.OAuth2.Client,
MSGraph.OAuth2.TokenStore,
MSGraph.Graph.Http,
MSGraph.Graph.Mail.Interfaces,
MSGraph.Graph.Mail,
MSGraph.Graph.Calendar.Interfaces,
MSGraph.Graph.Calendar,
MSGraph.Graph.Contacts.Interfaces,
MSGraph.Graph.Contacts,
MSGraph.Graph.SharePoint.Interfaces,
MSGraph.Graph.SharePoint;

Quick Start

1. Configure OAuth2

var Config: TOAuth2Config;
Config.ClientId := 'your-client-id';
Config.ClientSecret := 'your-client-secret';
Config.TenantId := 'your-tenant-id';
Config.RedirectUri := 'http://localhost:8080/oauth/callback';
Config.Scopes := TArray<string>.Create(
'openid', 'offline_access',
'Mail.Read', 'Mail.ReadWrite', 'Mail.Send',
'Calendars.ReadWrite', 'Contacts.ReadWrite',
'Sites.Read.All', 'User.Read'
);

2. Authenticate with PKCE

var PKCESession := TOAuth2PKCE.Generate;
var OAuthClient := TOAuth2Client.Create(Config);
var AuthUrl := OAuthClient.GenerateAuthorizationUrl(PKCESession);
// Open AuthUrl in browser, handle callback to receive authorization codevar Tokens := OAuthClient.ExchangeCodeForToken(Code, PKCESession.CodeVerifier);

3. Use Graph Clients

var Mail: IMailClient := TMailClient.Create(Tokens.AccessToken);
var SearchResult := Mail.SearchMessages('*', '', 10, 0);
forvar Msg in SearchResult.Messages do
WriteLn(Msg.Subject, ' - ', Msg.From.Address);

4. Refresh Tokens

if Tokens.IsExpiringSoon(300) thenbeginvar NewTokens := OAuthClient.RefreshAccessToken(Tokens.RefreshToken);
if NewTokens.RefreshToken.IsEmpty then
NewTokens.RefreshToken := Tokens.RefreshToken;
end;

5. Share a Single HTTP Client

All Graph clients accept an existing TGraphHttpClient, allowing you to share one connection across multiple services:

var Http := TGraphHttpClient.Create(Tokens.AccessToken);
var Mail: IMailClient := TMailClient.Create(Http);
var Calendar: ICalendarClient := TCalendarClient.Create(Http);

6. Access Shared Mailboxes

Set MailboxAddress on TGraphHttpClient to target a shared or delegated mailbox. When empty (default), endpoints use /me. When set, endpoints use /users/{address}:

var Http := TGraphHttpClient.Create(Tokens.AccessToken);
Http.MailboxAddress := 'projects@company.com';
var Mail: IMailClient := TMailClient.Create(Http);
var Messages := Mail.SearchMessages('*', '', 10, 0);

This requires the Mail.Read.Shared and/or Mail.Send.Shared delegated permissions in your Azure AD app registration.

7. Add Custom Internet Message Headers

CreateDraft has an overload that takes custom headers. They are written to the message as internetMessageHeaders and travel with it when the draft is sent:

var Draft := Mail.CreateDraft('Subject', 'Body', ['recipient@company.com'], [], [], False,
[TMailHeader.Create('x-example-id', '42')]);
Mail.SendDraft(Draft.Id);

Microsoft Graph requires a custom header name to start with x-, and accepts at most five custom headers per message. The library validates the headers before sending anything and raises EInvalidMailHeaderException with a readable message when a rule is broken:

RuleRejected example
At most five custom headers per messagesix headers
The name must not be empty''
The name must start with x- (case insensitive)Example-Id
The name may contain printable ASCII only, and no :x-example-id:42, x-example-id
The value must not contain control characters or line separators42<CR><LF>x-injected: yes
The same name must not be supplied twice (case insensitive)x-example-id and X-Example-Id

Names are sent exactly as supplied — the library does not change their casing.

Graph accepts internetMessageHeaders only when a message is created, so UpdateDraft does not offer this parameter.

Two things to know about the receiving side. Exchange Online maps a custom header name to a named property on first use, and does not store the value on that very first message — only later messages carrying the same header name keep their value. A transport rule or the header firewall can also strip custom headers in transit.

Project Structure

Source/
OAuth2/
MSGraph.OAuth2.Types.pas -Config records, token response, PKCE session, exceptions
MSGraph.OAuth2.PKCE.pas -PKCE code_verifier + code_challenge generation
MSGraph.OAuth2.Client.pas -OAuth2 flow: auth URL, token exchange, refresh
MSGraph.OAuth2.TokenStore.pas -Thread-safe in-memory token + PKCE storage
Graph/
MSGraph.Graph.Http.pas -Graph API HTTP client with error handling
MSGraph.Graph.JsonHelper.pas -JSON parsing utilities (TGraphJson)
MSGraph.Graph.Mail.Types.pas -Mail record types (TMailMessage, TMailFolder, etc.)
MSGraph.Graph.Mail.Interfaces.pas -IMailClient interface
MSGraph.Graph.Mail.pas -TMailClient implementation
MSGraph.Graph.Calendar.Types.pas -Calendar record types (TCalendarEvent, TAttendee, etc.)
MSGraph.Graph.Calendar.Interfaces.pas -ICalendarClient interface
MSGraph.Graph.Calendar.pas -TCalendarClient implementation
MSGraph.Graph.Contacts.Types.pas -Contact record types (TContact, TPostalAddress, etc.)
MSGraph.Graph.Contacts.Interfaces.pas -IContactsClient interface
MSGraph.Graph.Contacts.pas -TContactsClient implementation
MSGraph.Graph.SharePoint.Types.pas -SharePoint record types (TSite, TDriveItem)
MSGraph.Graph.SharePoint.Interfaces.pas -ISharePointClient interface
MSGraph.Graph.SharePoint.pas -TSharePointClient implementation
Examples/
Microsoft365Demo.dpr -Console demo with interactive menu
Microsoft365Demo.App.pas -Demo application logic
Microsoft365Demo.CallbackServer.pas -Indy HTTP server for OAuth callback

API Reference

Exception Hierarchy

All library exceptions inherit from EMSGraphException:

ExceptionRaised by
EMSGraphExceptionBase exception for all Microsoft365-4D errors
EOAuth2ExceptionToken exchange failures, invalid responses
EGraphApiExceptionGraph API HTTP errors, missing access token
ETokenStoreExceptionMissing tokens, expired PKCE sessions
EInvalidMailHeaderExceptionInvalid custom mail header supplied by the caller
EDeltaLinkExpiredExceptionAn expired delta link, so a full resynchronisation is needed

TMailClient

MethodDescription
SearchMessages(Query, FolderId, Top, Skip)Search or list messages
GetMessage(MessageId)Get full message by ID
GetMessageAttachments(MessageId)List attachments
GetAttachmentContent(MessageId, AttachmentId)Get attachment content
CreateDraft(Subject, Body, To, Cc, Bcc, IsHtml)Create draft
CreateDraft(Subject, Body, To, Cc, Bcc, IsHtml, Headers)Create draft with custom internet message headers
UpdateDraft(MessageId, Subject, Body, To, Cc, Bcc, IsHtml)Update existing draft
SendDraft(MessageId)Send a draft message
DeleteDraft(MessageId)Delete a draft
MoveMessage(MessageId, FolderId)Move message to folder
ListMailFolders(ParentFolderId)List mail folders
GetMailboxSignatureGet HTML signature

TCalendarClient

MethodDescription
ListEvents(Start, End, Top, Timezone)List calendar events in range
GetEvent(EventId)Get event details
CreateEvent(Subject, Start, End, Location, Body, Attendees, IsAllDay)Create event
UpdateEvent(EventId, Subject, Start, End, Location, Body, Attendees, IsAllDay)Update event
DeleteEvent(EventId)Delete event
GetScheduleAvailability(Schedules, Start, End, Timezone)Check availability

TContactsClient

MethodDescription
SearchContacts(Query, Top)Search or list contacts
GetContact(ContactId)Get contact details
CreateContact(GivenName, Surname, Email, Phone, Company, JobTitle)Create contact
UpdateContact(ContactId, GivenName, Surname, Email, Phone, Company, JobTitle)Update contact
DeleteContact(ContactId)Delete contact

TSharePointClient

MethodDescription
ListSites(Query, Top)Search SharePoint sites
GetSite(SiteId)Get site details
ListDriveItems(SiteId, FolderId, Top)List items in drive/folder
SearchDriveItems(SiteId, Query, Top)Search drive items
GetDriveItemContent(SiteId, ItemId)Get item details + download URL

Demo Application

The Examples/ folder contains a console application demonstrating the full OAuth2 flow and all Graph API operations.

Running the Demo

Microsoft365Demo.exe --client-id "your-id" --client-secret "your-secret" --tenant-id "your-tenant" --redirect-uri "http://localhost:8080/oauth/callback"

All parameters can also be provided interactively when omitted. Available options:

ParameterDescriptionDefault
--client-idAzure AD application ID(prompted)
--client-secretAzure AD client secret(prompted)
--tenant-idAzure AD tenant ID(prompted)
--redirect-uriOAuth2 redirect URIhttp://localhost:8080/oauth/callback
--portLocal callback server port8080

Demo Menu

The demo provides an interactive menu with the following options:

  1. Authenticate (opens browser for Microsoft login)
  2. List messages
  3. Read message by ID
  4. Send email (create draft + send)
  5. List mail folders
  6. List calendar events
  7. Create calendar event
  8. Search contacts
  9. List SharePoint sites
  10. Refresh token manually

Azure AD App Registration

  1. Go to Azure Portal > Microsoft Entra ID > App registrations > New registration
  2. Set Redirect URI to your callback URL (Web platform), e.g. http://localhost:8080/oauth/callback
  3. Create a Client secret under Certificates & secrets
  4. Add API permissions (Microsoft Graph, Delegated):
PermissionDescription
openidSign-in
profileUser profile
offline_accessRefresh tokens
Mail.ReadRead mail
Mail.ReadWriteCreate/edit drafts
Mail.SendSend mail
MailboxSettings.ReadRead mailbox signature
Calendars.ReadWriteCalendar access
Contacts.ReadWriteContacts access
Sites.Read.AllSharePoint read access
User.ReadUser info
Mail.Read.SharedRead shared/delegated mailboxes
Mail.Send.SharedSend from shared/delegated mailboxes
  1. Click Grant admin consent if you have admin rights

Token Storage

The included TTokenStore stores tokens in-memory only and is intended for demo/development use. For production:

  • Persist tokens to a database, file, or OS-level credential store
  • Encrypt refresh tokens and access tokens before storage
  • Implement your own storage by subclassing or replacing TTokenStore

License

MIT License. See LICENSE for details.

Commercial Support

This library is MIT licensed and free to use. For companies that depend on it commercially we offer support and maintenance agreements with guaranteed response times, and sponsored development of features you need. Contact us at gdksoftware.com/contact-us or open an issue to get in touch.

About GDK Software

Microsoft365-4D is developed by GDK Software, a Delphi-focused software company building developer tools, MCP integrations, and enterprise applications.

About

Delphi library for Microsoft 365 integration. OAuth2 with PKCE, Mail, Calendar, Contacts, and SharePoint via Microsoft Graph API. No external dependencies.

Resources

Stars

35 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Microsoft365-4D

Delphi VersionPlatformLicense

Pure Delphi library for Microsoft Graph API integration. Provides OAuth2 authentication with PKCE and typed clients for Mail, Calendar, Contacts, and SharePoint. No external dependencies beyond the Delphi RTL.

Table of Contents

Features

  • OAuth2 + PKCE authentication flow for Microsoft identity platform
  • Mail -search, read, draft, send, delete, move messages, list folders, attachments
  • Calendar -list, create, update, delete events, check schedule availability
  • Contacts -search, create, update, delete contacts
  • SharePoint -browse sites, list/search drive items, get file content
  • Zero dependencies -uses only System.Net.HttpClient (Delphi RTL)
  • Pluggable logging -TLogProc callback, no global logger
  • Shared HTTP client -all Graph clients can share a single TGraphHttpClient
  • Shared mailbox support -access shared/delegated mailboxes via MailboxAddress property
  • Typed responses -all API calls return strongly-typed records (TMailMessage, TCalendarEvent, etc.)
  • Interface-based -all clients implement interfaces (IMailClient, ICalendarClient, etc.) for dependency injection

Requirements

  • Delphi 11 Alexandria or later (RAD Studio 11.x+)
  • Azure AD App Registration with appropriate API permissions

Installation

Using as a Library

Add the Source/OAuth2 and Source/Graph directories to your project's search path:

Source\OAuth2;Source\Graph

Then add the units you need to your uses clause:

uses
MSGraph.OAuth2.Types,
MSGraph.OAuth2.PKCE,
MSGraph.OAuth2.Client,
MSGraph.OAuth2.TokenStore,
MSGraph.Graph.Http,
MSGraph.Graph.Mail.Interfaces,
MSGraph.Graph.Mail,
MSGraph.Graph.Calendar.Interfaces,
MSGraph.Graph.Calendar,
MSGraph.Graph.Contacts.Interfaces,
MSGraph.Graph.Contacts,
MSGraph.Graph.SharePoint.Interfaces,
MSGraph.Graph.SharePoint;

Quick Start

1. Configure OAuth2

var Config: TOAuth2Config;
Config.ClientId := 'your-client-id';
Config.ClientSecret := 'your-client-secret';
Config.TenantId := 'your-tenant-id';
Config.RedirectUri := 'http://localhost:8080/oauth/callback';
Config.Scopes := TArray<string>.Create(
'openid', 'offline_access',
'Mail.Read', 'Mail.ReadWrite', 'Mail.Send',
'Calendars.ReadWrite', 'Contacts.ReadWrite',
'Sites.Read.All', 'User.Read'
);

2. Authenticate with PKCE

var PKCESession := TOAuth2PKCE.Generate;
var OAuthClient := TOAuth2Client.Create(Config);
var AuthUrl := OAuthClient.GenerateAuthorizationUrl(PKCESession);
// Open AuthUrl in browser, handle callback to receive authorization codevar Tokens := OAuthClient.ExchangeCodeForToken(Code, PKCESession.CodeVerifier);

3. Use Graph Clients

var Mail: IMailClient := TMailClient.Create(Tokens.AccessToken);
var SearchResult := Mail.SearchMessages('*', '', 10, 0);
forvar Msg in SearchResult.Messages do
WriteLn(Msg.Subject, ' - ', Msg.From.Address);

4. Refresh Tokens

if Tokens.IsExpiringSoon(300) thenbeginvar NewTokens := OAuthClient.RefreshAccessToken(Tokens.RefreshToken);
if NewTokens.RefreshToken.IsEmpty then
NewTokens.RefreshToken := Tokens.RefreshToken;
end;

5. Share a Single HTTP Client

All Graph clients accept an existing TGraphHttpClient, allowing you to share one connection across multiple services:

var Http := TGraphHttpClient.Create(Tokens.AccessToken);
var Mail: IMailClient := TMailClient.Create(Http);
var Calendar: ICalendarClient := TCalendarClient.Create(Http);

6. Access Shared Mailboxes

Set MailboxAddress on TGraphHttpClient to target a shared or delegated mailbox. When empty (default), endpoints use /me. When set, endpoints use /users/{address}:

var Http := TGraphHttpClient.Create(Tokens.AccessToken);
Http.MailboxAddress := 'projects@company.com';
var Mail: IMailClient := TMailClient.Create(Http);
var Messages := Mail.SearchMessages('*', '', 10, 0);

This requires the Mail.Read.Shared and/or Mail.Send.Shared delegated permissions in your Azure AD app registration.

7. Add Custom Internet Message Headers

CreateDraft has an overload that takes custom headers. They are written to the message as internetMessageHeaders and travel with it when the draft is sent:

var Draft := Mail.CreateDraft('Subject', 'Body', ['recipient@company.com'], [], [], False,
[TMailHeader.Create('x-example-id', '42')]);
Mail.SendDraft(Draft.Id);

Microsoft Graph requires a custom header name to start with x-, and accepts at most five custom headers per message. The library validates the headers before sending anything and raises EInvalidMailHeaderException with a readable message when a rule is broken:

RuleRejected example
At most five custom headers per messagesix headers
The name must not be empty''
The name must start with x- (case insensitive)Example-Id
The name may contain printable ASCII only, and no :x-example-id:42, x-example-id
The value must not contain control characters or line separators42<CR><LF>x-injected: yes
The same name must not be supplied twice (case insensitive)x-example-id and X-Example-Id

Names are sent exactly as supplied — the library does not change their casing.

Graph accepts internetMessageHeaders only when a message is created, so UpdateDraft does not offer this parameter.

Two things to know about the receiving side. Exchange Online maps a custom header name to a named property on first use, and does not store the value on that very first message — only later messages carrying the same header name keep their value. A transport rule or the header firewall can also strip custom headers in transit.

Project Structure

Source/
OAuth2/
MSGraph.OAuth2.Types.pas -Config records, token response, PKCE session, exceptions
MSGraph.OAuth2.PKCE.pas -PKCE code_verifier + code_challenge generation
MSGraph.OAuth2.Client.pas -OAuth2 flow: auth URL, token exchange, refresh
MSGraph.OAuth2.TokenStore.pas -Thread-safe in-memory token + PKCE storage
Graph/
MSGraph.Graph.Http.pas -Graph API HTTP client with error handling
MSGraph.Graph.JsonHelper.pas -JSON parsing utilities (TGraphJson)
MSGraph.Graph.Mail.Types.pas -Mail record types (TMailMessage, TMailFolder, etc.)
MSGraph.Graph.Mail.Interfaces.pas -IMailClient interface
MSGraph.Graph.Mail.pas -TMailClient implementation
MSGraph.Graph.Calendar.Types.pas -Calendar record types (TCalendarEvent, TAttendee, etc.)
MSGraph.Graph.Calendar.Interfaces.pas -ICalendarClient interface
MSGraph.Graph.Calendar.pas -TCalendarClient implementation
MSGraph.Graph.Contacts.Types.pas -Contact record types (TContact, TPostalAddress, etc.)
MSGraph.Graph.Contacts.Interfaces.pas -IContactsClient interface
MSGraph.Graph.Contacts.pas -TContactsClient implementation
MSGraph.Graph.SharePoint.Types.pas -SharePoint record types (TSite, TDriveItem)
MSGraph.Graph.SharePoint.Interfaces.pas -ISharePointClient interface
MSGraph.Graph.SharePoint.pas -TSharePointClient implementation
Examples/
Microsoft365Demo.dpr -Console demo with interactive menu
Microsoft365Demo.App.pas -Demo application logic
Microsoft365Demo.CallbackServer.pas -Indy HTTP server for OAuth callback

API Reference

Exception Hierarchy

All library exceptions inherit from EMSGraphException:

ExceptionRaised by
EMSGraphExceptionBase exception for all Microsoft365-4D errors
EOAuth2ExceptionToken exchange failures, invalid responses
EGraphApiExceptionGraph API HTTP errors, missing access token
ETokenStoreExceptionMissing tokens, expired PKCE sessions
EInvalidMailHeaderExceptionInvalid custom mail header supplied by the caller
EDeltaLinkExpiredExceptionAn expired delta link, so a full resynchronisation is needed

TMailClient

MethodDescription
SearchMessages(Query, FolderId, Top, Skip)Search or list messages
GetMessage(MessageId)Get full message by ID
GetMessageAttachments(MessageId)List attachments
GetAttachmentContent(MessageId, AttachmentId)Get attachment content
CreateDraft(Subject, Body, To, Cc, Bcc, IsHtml)Create draft
CreateDraft(Subject, Body, To, Cc, Bcc, IsHtml, Headers)Create draft with custom internet message headers
UpdateDraft(MessageId, Subject, Body, To, Cc, Bcc, IsHtml)Update existing draft
SendDraft(MessageId)Send a draft message
DeleteDraft(MessageId)Delete a draft
MoveMessage(MessageId, FolderId)Move message to folder
ListMailFolders(ParentFolderId)List mail folders
GetMailboxSignatureGet HTML signature

TCalendarClient

MethodDescription
ListEvents(Start, End, Top, Timezone)List calendar events in range
GetEvent(EventId)Get event details
CreateEvent(Subject, Start, End, Location, Body, Attendees, IsAllDay)Create event
UpdateEvent(EventId, Subject, Start, End, Location, Body, Attendees, IsAllDay)Update event
DeleteEvent(EventId)Delete event
GetScheduleAvailability(Schedules, Start, End, Timezone)Check availability

TContactsClient

MethodDescription
SearchContacts(Query, Top)Search or list contacts
GetContact(ContactId)Get contact details
CreateContact(GivenName, Surname, Email, Phone, Company, JobTitle)Create contact
UpdateContact(ContactId, GivenName, Surname, Email, Phone, Company, JobTitle)Update contact
DeleteContact(ContactId)Delete contact

TSharePointClient

MethodDescription
ListSites(Query, Top)Search SharePoint sites
GetSite(SiteId)Get site details
ListDriveItems(SiteId, FolderId, Top)List items in drive/folder
SearchDriveItems(SiteId, Query, Top)Search drive items
GetDriveItemContent(SiteId, ItemId)Get item details + download URL

Demo Application

The Examples/ folder contains a console application demonstrating the full OAuth2 flow and all Graph API operations.

Running the Demo

Microsoft365Demo.exe --client-id "your-id" --client-secret "your-secret" --tenant-id "your-tenant" --redirect-uri "http://localhost:8080/oauth/callback"

All parameters can also be provided interactively when omitted. Available options:

ParameterDescriptionDefault
--client-idAzure AD application ID(prompted)
--client-secretAzure AD client secret(prompted)
--tenant-idAzure AD tenant ID(prompted)
--redirect-uriOAuth2 redirect URIhttp://localhost:8080/oauth/callback
--portLocal callback server port8080

Demo Menu

The demo provides an interactive menu with the following options:

  1. Authenticate (opens browser for Microsoft login)
  2. List messages
  3. Read message by ID
  4. Send email (create draft + send)
  5. List mail folders
  6. List calendar events
  7. Create calendar event
  8. Search contacts
  9. List SharePoint sites
  10. Refresh token manually

Azure AD App Registration

  1. Go to Azure Portal > Microsoft Entra ID > App registrations > New registration
  2. Set Redirect URI to your callback URL (Web platform), e.g. http://localhost:8080/oauth/callback
  3. Create a Client secret under Certificates & secrets
  4. Add API permissions (Microsoft Graph, Delegated):
PermissionDescription
openidSign-in
profileUser profile
offline_accessRefresh tokens
Mail.ReadRead mail
Mail.ReadWriteCreate/edit drafts
Mail.SendSend mail
MailboxSettings.ReadRead mailbox signature
Calendars.ReadWriteCalendar access
Contacts.ReadWriteContacts access
Sites.Read.AllSharePoint read access
User.ReadUser info
Mail.Read.SharedRead shared/delegated mailboxes
Mail.Send.SharedSend from shared/delegated mailboxes
  1. Click Grant admin consent if you have admin rights

Token Storage

The included TTokenStore stores tokens in-memory only and is intended for demo/development use. For production:

  • Persist tokens to a database, file, or OS-level credential store
  • Encrypt refresh tokens and access tokens before storage
  • Implement your own storage by subclassing or replacing TTokenStore

License

MIT License. See LICENSE for details.

Commercial Support

This library is MIT licensed and free to use. For companies that depend on it commercially we offer support and maintenance agreements with guaranteed response times, and sponsored development of features you need. Contact us at gdksoftware.com/contact-us or open an issue to get in touch.

About GDK Software

Microsoft365-4D is developed by GDK Software, a Delphi-focused software company building developer tools, MCP integrations, and enterprise applications.

About

Delphi library for Microsoft 365 integration. OAuth2 with PKCE, Mail, Calendar, Contacts, and SharePoint via Microsoft Graph API. No external dependencies.

Resources

Stars

35 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Microsoft365-4D

Delphi VersionPlatformLicense

Pure Delphi library for Microsoft Graph API integration. Provides OAuth2 authentication with PKCE and typed clients for Mail, Calendar, Contacts, and SharePoint. No external dependencies beyond the Delphi RTL.

Table of Contents

Features

  • OAuth2 + PKCE authentication flow for Microsoft identity platform
  • Mail -search, read, draft, send, delete, move messages, list folders, attachments
  • Calendar -list, create, update, delete events, check schedule availability
  • Contacts -search, create, update, delete contacts
  • SharePoint -browse sites, list/search drive items, get file content
  • Zero dependencies -uses only System.Net.HttpClient (Delphi RTL)
  • Pluggable logging -TLogProc callback, no global logger
  • Shared HTTP client -all Graph clients can share a single TGraphHttpClient
  • Shared mailbox support -access shared/delegated mailboxes via MailboxAddress property
  • Typed responses -all API calls return strongly-typed records (TMailMessage, TCalendarEvent, etc.)
  • Interface-based -all clients implement interfaces (IMailClient, ICalendarClient, etc.) for dependency injection

Requirements

  • Delphi 11 Alexandria or later (RAD Studio 11.x+)
  • Azure AD App Registration with appropriate API permissions

Installation

Using as a Library

Add the Source/OAuth2 and Source/Graph directories to your project's search path:

Source\OAuth2;Source\Graph

Then add the units you need to your uses clause:

uses
MSGraph.OAuth2.Types,
MSGraph.OAuth2.PKCE,
MSGraph.OAuth2.Client,
MSGraph.OAuth2.TokenStore,
MSGraph.Graph.Http,
MSGraph.Graph.Mail.Interfaces,
MSGraph.Graph.Mail,
MSGraph.Graph.Calendar.Interfaces,
MSGraph.Graph.Calendar,
MSGraph.Graph.Contacts.Interfaces,
MSGraph.Graph.Contacts,
MSGraph.Graph.SharePoint.Interfaces,
MSGraph.Graph.SharePoint;

Quick Start

1. Configure OAuth2

var Config: TOAuth2Config;
Config.ClientId := 'your-client-id';
Config.ClientSecret := 'your-client-secret';
Config.TenantId := 'your-tenant-id';
Config.RedirectUri := 'http://localhost:8080/oauth/callback';
Config.Scopes := TArray<string>.Create(
'openid', 'offline_access',
'Mail.Read', 'Mail.ReadWrite', 'Mail.Send',
'Calendars.ReadWrite', 'Contacts.ReadWrite',
'Sites.Read.All', 'User.Read'
);

2. Authenticate with PKCE

var PKCESession := TOAuth2PKCE.Generate;
var OAuthClient := TOAuth2Client.Create(Config);
var AuthUrl := OAuthClient.GenerateAuthorizationUrl(PKCESession);
// Open AuthUrl in browser, handle callback to receive authorization codevar Tokens := OAuthClient.ExchangeCodeForToken(Code, PKCESession.CodeVerifier);

3. Use Graph Clients

var Mail: IMailClient := TMailClient.Create(Tokens.AccessToken);
var SearchResult := Mail.SearchMessages('*', '', 10, 0);
forvar Msg in SearchResult.Messages do
WriteLn(Msg.Subject, ' - ', Msg.From.Address);

4. Refresh Tokens

if Tokens.IsExpiringSoon(300) thenbeginvar NewTokens := OAuthClient.RefreshAccessToken(Tokens.RefreshToken);
if NewTokens.RefreshToken.IsEmpty then
NewTokens.RefreshToken := Tokens.RefreshToken;
end;

5. Share a Single HTTP Client

All Graph clients accept an existing TGraphHttpClient, allowing you to share one connection across multiple services:

var Http := TGraphHttpClient.Create(Tokens.AccessToken);
var Mail: IMailClient := TMailClient.Create(Http);
var Calendar: ICalendarClient := TCalendarClient.Create(Http);

6. Access Shared Mailboxes

Set MailboxAddress on TGraphHttpClient to target a shared or delegated mailbox. When empty (default), endpoints use /me. When set, endpoints use /users/{address}:

var Http := TGraphHttpClient.Create(Tokens.AccessToken);
Http.MailboxAddress := 'projects@company.com';
var Mail: IMailClient := TMailClient.Create(Http);
var Messages := Mail.SearchMessages('*', '', 10, 0);

This requires the Mail.Read.Shared and/or Mail.Send.Shared delegated permissions in your Azure AD app registration.

7. Add Custom Internet Message Headers

CreateDraft has an overload that takes custom headers. They are written to the message as internetMessageHeaders and travel with it when the draft is sent:

var Draft := Mail.CreateDraft('Subject', 'Body', ['recipient@company.com'], [], [], False,
[TMailHeader.Create('x-example-id', '42')]);
Mail.SendDraft(Draft.Id);

Microsoft Graph requires a custom header name to start with x-, and accepts at most five custom headers per message. The library validates the headers before sending anything and raises EInvalidMailHeaderException with a readable message when a rule is broken:

RuleRejected example
At most five custom headers per messagesix headers
The name must not be empty''
The name must start with x- (case insensitive)Example-Id
The name may contain printable ASCII only, and no :x-example-id:42, x-example-id
The value must not contain control characters or line separators42<CR><LF>x-injected: yes
The same name must not be supplied twice (case insensitive)x-example-id and X-Example-Id

Names are sent exactly as supplied — the library does not change their casing.

Graph accepts internetMessageHeaders only when a message is created, so UpdateDraft does not offer this parameter.

Two things to know about the receiving side. Exchange Online maps a custom header name to a named property on first use, and does not store the value on that very first message — only later messages carrying the same header name keep their value. A transport rule or the header firewall can also strip custom headers in transit.

Project Structure

Source/
OAuth2/
MSGraph.OAuth2.Types.pas -Config records, token response, PKCE session, exceptions
MSGraph.OAuth2.PKCE.pas -PKCE code_verifier + code_challenge generation
MSGraph.OAuth2.Client.pas -OAuth2 flow: auth URL, token exchange, refresh
MSGraph.OAuth2.TokenStore.pas -Thread-safe in-memory token + PKCE storage
Graph/
MSGraph.Graph.Http.pas -Graph API HTTP client with error handling
MSGraph.Graph.JsonHelper.pas -JSON parsing utilities (TGraphJson)
MSGraph.Graph.Mail.Types.pas -Mail record types (TMailMessage, TMailFolder, etc.)
MSGraph.Graph.Mail.Interfaces.pas -IMailClient interface
MSGraph.Graph.Mail.pas -TMailClient implementation
MSGraph.Graph.Calendar.Types.pas -Calendar record types (TCalendarEvent, TAttendee, etc.)
MSGraph.Graph.Calendar.Interfaces.pas -ICalendarClient interface
MSGraph.Graph.Calendar.pas -TCalendarClient implementation
MSGraph.Graph.Contacts.Types.pas -Contact record types (TContact, TPostalAddress, etc.)
MSGraph.Graph.Contacts.Interfaces.pas -IContactsClient interface
MSGraph.Graph.Contacts.pas -TContactsClient implementation
MSGraph.Graph.SharePoint.Types.pas -SharePoint record types (TSite, TDriveItem)
MSGraph.Graph.SharePoint.Interfaces.pas -ISharePointClient interface
MSGraph.Graph.SharePoint.pas -TSharePointClient implementation
Examples/
Microsoft365Demo.dpr -Console demo with interactive menu
Microsoft365Demo.App.pas -Demo application logic
Microsoft365Demo.CallbackServer.pas -Indy HTTP server for OAuth callback

API Reference

Exception Hierarchy

All library exceptions inherit from EMSGraphException:

ExceptionRaised by
EMSGraphExceptionBase exception for all Microsoft365-4D errors
EOAuth2ExceptionToken exchange failures, invalid responses
EGraphApiExceptionGraph API HTTP errors, missing access token
ETokenStoreExceptionMissing tokens, expired PKCE sessions
EInvalidMailHeaderExceptionInvalid custom mail header supplied by the caller
EDeltaLinkExpiredExceptionAn expired delta link, so a full resynchronisation is needed

TMailClient

MethodDescription
SearchMessages(Query, FolderId, Top, Skip)Search or list messages
GetMessage(MessageId)Get full message by ID
GetMessageAttachments(MessageId)List attachments
GetAttachmentContent(MessageId, AttachmentId)Get attachment content
CreateDraft(Subject, Body, To, Cc, Bcc, IsHtml)Create draft
CreateDraft(Subject, Body, To, Cc, Bcc, IsHtml, Headers)Create draft with custom internet message headers
UpdateDraft(MessageId, Subject, Body, To, Cc, Bcc, IsHtml)Update existing draft
SendDraft(MessageId)Send a draft message
DeleteDraft(MessageId)Delete a draft
MoveMessage(MessageId, FolderId)Move message to folder
ListMailFolders(ParentFolderId)List mail folders
GetMailboxSignatureGet HTML signature

TCalendarClient

MethodDescription
ListEvents(Start, End, Top, Timezone)List calendar events in range
GetEvent(EventId)Get event details
CreateEvent(Subject, Start, End, Location, Body, Attendees, IsAllDay)Create event
UpdateEvent(EventId, Subject, Start, End, Location, Body, Attendees, IsAllDay)Update event
DeleteEvent(EventId)Delete event
GetScheduleAvailability(Schedules, Start, End, Timezone)Check availability

TContactsClient

MethodDescription
SearchContacts(Query, Top)Search or list contacts
GetContact(ContactId)Get contact details
CreateContact(GivenName, Surname, Email, Phone, Company, JobTitle)Create contact
UpdateContact(ContactId, GivenName, Surname, Email, Phone, Company, JobTitle)Update contact
DeleteContact(ContactId)Delete contact

TSharePointClient

MethodDescription
ListSites(Query, Top)Search SharePoint sites
GetSite(SiteId)Get site details
ListDriveItems(SiteId, FolderId, Top)List items in drive/folder
SearchDriveItems(SiteId, Query, Top)Search drive items
GetDriveItemContent(SiteId, ItemId)Get item details + download URL

Demo Application

The Examples/ folder contains a console application demonstrating the full OAuth2 flow and all Graph API operations.

Running the Demo

Microsoft365Demo.exe --client-id "your-id" --client-secret "your-secret" --tenant-id "your-tenant" --redirect-uri "http://localhost:8080/oauth/callback"

All parameters can also be provided interactively when omitted. Available options:

ParameterDescriptionDefault
--client-idAzure AD application ID(prompted)
--client-secretAzure AD client secret(prompted)
--tenant-idAzure AD tenant ID(prompted)
--redirect-uriOAuth2 redirect URIhttp://localhost:8080/oauth/callback
--portLocal callback server port8080

Demo Menu

The demo provides an interactive menu with the following options:

  1. Authenticate (opens browser for Microsoft login)
  2. List messages
  3. Read message by ID
  4. Send email (create draft + send)
  5. List mail folders
  6. List calendar events
  7. Create calendar event
  8. Search contacts
  9. List SharePoint sites
  10. Refresh token manually

Azure AD App Registration

  1. Go to Azure Portal > Microsoft Entra ID > App registrations > New registration
  2. Set Redirect URI to your callback URL (Web platform), e.g. http://localhost:8080/oauth/callback
  3. Create a Client secret under Certificates & secrets
  4. Add API permissions (Microsoft Graph, Delegated):
PermissionDescription
openidSign-in
profileUser profile
offline_accessRefresh tokens
Mail.ReadRead mail
Mail.ReadWriteCreate/edit drafts
Mail.SendSend mail
MailboxSettings.ReadRead mailbox signature
Calendars.ReadWriteCalendar access
Contacts.ReadWriteContacts access
Sites.Read.AllSharePoint read access
User.ReadUser info
Mail.Read.SharedRead shared/delegated mailboxes
Mail.Send.SharedSend from shared/delegated mailboxes
  1. Click Grant admin consent if you have admin rights

Token Storage

The included TTokenStore stores tokens in-memory only and is intended for demo/development use. For production:

  • Persist tokens to a database, file, or OS-level credential store
  • Encrypt refresh tokens and access tokens before storage
  • Implement your own storage by subclassing or replacing TTokenStore

License

MIT License. See LICENSE for details.

Commercial Support

This library is MIT licensed and free to use. For companies that depend on it commercially we offer support and maintenance agreements with guaranteed response times, and sponsored development of features you need. Contact us at gdksoftware.com/contact-us or open an issue to get in touch.

About GDK Software

Microsoft365-4D is developed by GDK Software, a Delphi-focused software company building developer tools, MCP integrations, and enterprise applications.

About

Delphi library for Microsoft 365 integration. OAuth2 with PKCE, Mail, Calendar, Contacts, and SharePoint via Microsoft Graph API. No external dependencies.

Resources

Stars

35 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Microsoft365-4D

Delphi VersionPlatformLicense

Pure Delphi library for Microsoft Graph API integration. Provides OAuth2 authentication with PKCE and typed clients for Mail, Calendar, Contacts, and SharePoint. No external dependencies beyond the Delphi RTL.

Table of Contents

Features

  • OAuth2 + PKCE authentication flow for Microsoft identity platform
  • Mail -search, read, draft, send, delete, move messages, list folders, attachments
  • Calendar -list, create, update, delete events, check schedule availability
  • Contacts -search, create, update, delete contacts
  • SharePoint -browse sites, list/search drive items, get file content
  • Zero dependencies -uses only System.Net.HttpClient (Delphi RTL)
  • Pluggable logging -TLogProc callback, no global logger
  • Shared HTTP client -all Graph clients can share a single TGraphHttpClient
  • Shared mailbox support -access shared/delegated mailboxes via MailboxAddress property
  • Typed responses -all API calls return strongly-typed records (TMailMessage, TCalendarEvent, etc.)
  • Interface-based -all clients implement interfaces (IMailClient, ICalendarClient, etc.) for dependency injection

Requirements

  • Delphi 11 Alexandria or later (RAD Studio 11.x+)
  • Azure AD App Registration with appropriate API permissions

Installation

Using as a Library

Add the Source/OAuth2 and Source/Graph directories to your project's search path:

Source\OAuth2;Source\Graph

Then add the units you need to your uses clause:

uses
MSGraph.OAuth2.Types,
MSGraph.OAuth2.PKCE,
MSGraph.OAuth2.Client,
MSGraph.OAuth2.TokenStore,
MSGraph.Graph.Http,
MSGraph.Graph.Mail.Interfaces,
MSGraph.Graph.Mail,
MSGraph.Graph.Calendar.Interfaces,
MSGraph.Graph.Calendar,
MSGraph.Graph.Contacts.Interfaces,
MSGraph.Graph.Contacts,
MSGraph.Graph.SharePoint.Interfaces,
MSGraph.Graph.SharePoint;

Quick Start

1. Configure OAuth2

var Config: TOAuth2Config;
Config.ClientId := 'your-client-id';
Config.ClientSecret := 'your-client-secret';
Config.TenantId := 'your-tenant-id';
Config.RedirectUri := 'http://localhost:8080/oauth/callback';
Config.Scopes := TArray<string>.Create(
'openid', 'offline_access',
'Mail.Read', 'Mail.ReadWrite', 'Mail.Send',
'Calendars.ReadWrite', 'Contacts.ReadWrite',
'Sites.Read.All', 'User.Read'
);

2. Authenticate with PKCE

var PKCESession := TOAuth2PKCE.Generate;
var OAuthClient := TOAuth2Client.Create(Config);
var AuthUrl := OAuthClient.GenerateAuthorizationUrl(PKCESession);
// Open AuthUrl in browser, handle callback to receive authorization codevar Tokens := OAuthClient.ExchangeCodeForToken(Code, PKCESession.CodeVerifier);

3. Use Graph Clients

var Mail: IMailClient := TMailClient.Create(Tokens.AccessToken);
var SearchResult := Mail.SearchMessages('*', '', 10, 0);
forvar Msg in SearchResult.Messages do
WriteLn(Msg.Subject, ' - ', Msg.From.Address);

4. Refresh Tokens

if Tokens.IsExpiringSoon(300) thenbeginvar NewTokens := OAuthClient.RefreshAccessToken(Tokens.RefreshToken);
if NewTokens.RefreshToken.IsEmpty then
NewTokens.RefreshToken := Tokens.RefreshToken;
end;

5. Share a Single HTTP Client

All Graph clients accept an existing TGraphHttpClient, allowing you to share one connection across multiple services:

var Http := TGraphHttpClient.Create(Tokens.AccessToken);
var Mail: IMailClient := TMailClient.Create(Http);
var Calendar: ICalendarClient := TCalendarClient.Create(Http);

6. Access Shared Mailboxes

Set MailboxAddress on TGraphHttpClient to target a shared or delegated mailbox. When empty (default), endpoints use /me. When set, endpoints use /users/{address}:

var Http := TGraphHttpClient.Create(Tokens.AccessToken);
Http.MailboxAddress := 'projects@company.com';
var Mail: IMailClient := TMailClient.Create(Http);
var Messages := Mail.SearchMessages('*', '', 10, 0);

This requires the Mail.Read.Shared and/or Mail.Send.Shared delegated permissions in your Azure AD app registration.

7. Add Custom Internet Message Headers

CreateDraft has an overload that takes custom headers. They are written to the message as internetMessageHeaders and travel with it when the draft is sent:

var Draft := Mail.CreateDraft('Subject', 'Body', ['recipient@company.com'], [], [], False,
[TMailHeader.Create('x-example-id', '42')]);
Mail.SendDraft(Draft.Id);

Microsoft Graph requires a custom header name to start with x-, and accepts at most five custom headers per message. The library validates the headers before sending anything and raises EInvalidMailHeaderException with a readable message when a rule is broken:

RuleRejected example
At most five custom headers per messagesix headers
The name must not be empty''
The name must start with x- (case insensitive)Example-Id
The name may contain printable ASCII only, and no :x-example-id:42, x-example-id
The value must not contain control characters or line separators42<CR><LF>x-injected: yes
The same name must not be supplied twice (case insensitive)x-example-id and X-Example-Id

Names are sent exactly as supplied — the library does not change their casing.

Graph accepts internetMessageHeaders only when a message is created, so UpdateDraft does not offer this parameter.

Two things to know about the receiving side. Exchange Online maps a custom header name to a named property on first use, and does not store the value on that very first message — only later messages carrying the same header name keep their value. A transport rule or the header firewall can also strip custom headers in transit.

Project Structure

Source/
OAuth2/
MSGraph.OAuth2.Types.pas -Config records, token response, PKCE session, exceptions
MSGraph.OAuth2.PKCE.pas -PKCE code_verifier + code_challenge generation
MSGraph.OAuth2.Client.pas -OAuth2 flow: auth URL, token exchange, refresh
MSGraph.OAuth2.TokenStore.pas -Thread-safe in-memory token + PKCE storage
Graph/
MSGraph.Graph.Http.pas -Graph API HTTP client with error handling
MSGraph.Graph.JsonHelper.pas -JSON parsing utilities (TGraphJson)
MSGraph.Graph.Mail.Types.pas -Mail record types (TMailMessage, TMailFolder, etc.)
MSGraph.Graph.Mail.Interfaces.pas -IMailClient interface
MSGraph.Graph.Mail.pas -TMailClient implementation
MSGraph.Graph.Calendar.Types.pas -Calendar record types (TCalendarEvent, TAttendee, etc.)
MSGraph.Graph.Calendar.Interfaces.pas -ICalendarClient interface
MSGraph.Graph.Calendar.pas -TCalendarClient implementation
MSGraph.Graph.Contacts.Types.pas -Contact record types (TContact, TPostalAddress, etc.)
MSGraph.Graph.Contacts.Interfaces.pas -IContactsClient interface
MSGraph.Graph.Contacts.pas -TContactsClient implementation
MSGraph.Graph.SharePoint.Types.pas -SharePoint record types (TSite, TDriveItem)
MSGraph.Graph.SharePoint.Interfaces.pas -ISharePointClient interface
MSGraph.Graph.SharePoint.pas -TSharePointClient implementation
Examples/
Microsoft365Demo.dpr -Console demo with interactive menu
Microsoft365Demo.App.pas -Demo application logic
Microsoft365Demo.CallbackServer.pas -Indy HTTP server for OAuth callback

API Reference

Exception Hierarchy

All library exceptions inherit from EMSGraphException:

ExceptionRaised by
EMSGraphExceptionBase exception for all Microsoft365-4D errors
EOAuth2ExceptionToken exchange failures, invalid responses
EGraphApiExceptionGraph API HTTP errors, missing access token
ETokenStoreExceptionMissing tokens, expired PKCE sessions
EInvalidMailHeaderExceptionInvalid custom mail header supplied by the caller
EDeltaLinkExpiredExceptionAn expired delta link, so a full resynchronisation is needed

TMailClient

MethodDescription
SearchMessages(Query, FolderId, Top, Skip)Search or list messages
GetMessage(MessageId)Get full message by ID
GetMessageAttachments(MessageId)List attachments
GetAttachmentContent(MessageId, AttachmentId)Get attachment content
CreateDraft(Subject, Body, To, Cc, Bcc, IsHtml)Create draft
CreateDraft(Subject, Body, To, Cc, Bcc, IsHtml, Headers)Create draft with custom internet message headers
UpdateDraft(MessageId, Subject, Body, To, Cc, Bcc, IsHtml)Update existing draft
SendDraft(MessageId)Send a draft message
DeleteDraft(MessageId)Delete a draft
MoveMessage(MessageId, FolderId)Move message to folder
ListMailFolders(ParentFolderId)List mail folders
GetMailboxSignatureGet HTML signature

TCalendarClient

MethodDescription
ListEvents(Start, End, Top, Timezone)List calendar events in range
GetEvent(EventId)Get event details
CreateEvent(Subject, Start, End, Location, Body, Attendees, IsAllDay)Create event
UpdateEvent(EventId, Subject, Start, End, Location, Body, Attendees, IsAllDay)Update event
DeleteEvent(EventId)Delete event
GetScheduleAvailability(Schedules, Start, End, Timezone)Check availability

TContactsClient

MethodDescription
SearchContacts(Query, Top)Search or list contacts
GetContact(ContactId)Get contact details
CreateContact(GivenName, Surname, Email, Phone, Company, JobTitle)Create contact
UpdateContact(ContactId, GivenName, Surname, Email, Phone, Company, JobTitle)Update contact
DeleteContact(ContactId)Delete contact

TSharePointClient

MethodDescription
ListSites(Query, Top)Search SharePoint sites
GetSite(SiteId)Get site details
ListDriveItems(SiteId, FolderId, Top)List items in drive/folder
SearchDriveItems(SiteId, Query, Top)Search drive items
GetDriveItemContent(SiteId, ItemId)Get item details + download URL

Demo Application

The Examples/ folder contains a console application demonstrating the full OAuth2 flow and all Graph API operations.

Running the Demo

Microsoft365Demo.exe --client-id "your-id" --client-secret "your-secret" --tenant-id "your-tenant" --redirect-uri "http://localhost:8080/oauth/callback"

All parameters can also be provided interactively when omitted. Available options:

ParameterDescriptionDefault
--client-idAzure AD application ID(prompted)
--client-secretAzure AD client secret(prompted)
--tenant-idAzure AD tenant ID(prompted)
--redirect-uriOAuth2 redirect URIhttp://localhost:8080/oauth/callback
--portLocal callback server port8080

Demo Menu

The demo provides an interactive menu with the following options:

  1. Authenticate (opens browser for Microsoft login)
  2. List messages
  3. Read message by ID
  4. Send email (create draft + send)
  5. List mail folders
  6. List calendar events
  7. Create calendar event
  8. Search contacts
  9. List SharePoint sites
  10. Refresh token manually

Azure AD App Registration

  1. Go to Azure Portal > Microsoft Entra ID > App registrations > New registration
  2. Set Redirect URI to your callback URL (Web platform), e.g. http://localhost:8080/oauth/callback
  3. Create a Client secret under Certificates & secrets
  4. Add API permissions (Microsoft Graph, Delegated):
PermissionDescription
openidSign-in
profileUser profile
offline_accessRefresh tokens
Mail.ReadRead mail
Mail.ReadWriteCreate/edit drafts
Mail.SendSend mail
MailboxSettings.ReadRead mailbox signature
Calendars.ReadWriteCalendar access
Contacts.ReadWriteContacts access
Sites.Read.AllSharePoint read access
User.ReadUser info
Mail.Read.SharedRead shared/delegated mailboxes
Mail.Send.SharedSend from shared/delegated mailboxes
  1. Click Grant admin consent if you have admin rights

Token Storage

The included TTokenStore stores tokens in-memory only and is intended for demo/development use. For production:

  • Persist tokens to a database, file, or OS-level credential store
  • Encrypt refresh tokens and access tokens before storage
  • Implement your own storage by subclassing or replacing TTokenStore

License

MIT License. See LICENSE for details.

Commercial Support

This library is MIT licensed and free to use. For companies that depend on it commercially we offer support and maintenance agreements with guaranteed response times, and sponsored development of features you need. Contact us at gdksoftware.com/contact-us or open an issue to get in touch.

About GDK Software

Microsoft365-4D is developed by GDK Software, a Delphi-focused software company building developer tools, MCP integrations, and enterprise applications.

About

Delphi library for Microsoft 365 integration. OAuth2 with PKCE, Mail, Calendar, Contacts, and SharePoint via Microsoft Graph API. No external dependencies.

Resources

Stars

35 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Microsoft365-4D

Delphi VersionPlatformLicense

Pure Delphi library for Microsoft Graph API integration. Provides OAuth2 authentication with PKCE and typed clients for Mail, Calendar, Contacts, and SharePoint. No external dependencies beyond the Delphi RTL.

Table of Contents

Features

  • OAuth2 + PKCE authentication flow for Microsoft identity platform
  • Mail -search, read, draft, send, delete, move messages, list folders, attachments
  • Calendar -list, create, update, delete events, check schedule availability
  • Contacts -search, create, update, delete contacts
  • SharePoint -browse sites, list/search drive items, get file content
  • Zero dependencies -uses only System.Net.HttpClient (Delphi RTL)
  • Pluggable logging -TLogProc callback, no global logger
  • Shared HTTP client -all Graph clients can share a single TGraphHttpClient
  • Shared mailbox support -access shared/delegated mailboxes via MailboxAddress property
  • Typed responses -all API calls return strongly-typed records (TMailMessage, TCalendarEvent, etc.)
  • Interface-based -all clients implement interfaces (IMailClient, ICalendarClient, etc.) for dependency injection

Requirements

  • Delphi 11 Alexandria or later (RAD Studio 11.x+)
  • Azure AD App Registration with appropriate API permissions

Installation

Using as a Library

Add the Source/OAuth2 and Source/Graph directories to your project's search path:

Source\OAuth2;Source\Graph

Then add the units you need to your uses clause:

uses
MSGraph.OAuth2.Types,
MSGraph.OAuth2.PKCE,
MSGraph.OAuth2.Client,
MSGraph.OAuth2.TokenStore,
MSGraph.Graph.Http,
MSGraph.Graph.Mail.Interfaces,
MSGraph.Graph.Mail,
MSGraph.Graph.Calendar.Interfaces,
MSGraph.Graph.Calendar,
MSGraph.Graph.Contacts.Interfaces,
MSGraph.Graph.Contacts,
MSGraph.Graph.SharePoint.Interfaces,
MSGraph.Graph.SharePoint;

Quick Start

1. Configure OAuth2

var Config: TOAuth2Config;
Config.ClientId := 'your-client-id';
Config.ClientSecret := 'your-client-secret';
Config.TenantId := 'your-tenant-id';
Config.RedirectUri := 'http://localhost:8080/oauth/callback';
Config.Scopes := TArray<string>.Create(
'openid', 'offline_access',
'Mail.Read', 'Mail.ReadWrite', 'Mail.Send',
'Calendars.ReadWrite', 'Contacts.ReadWrite',
'Sites.Read.All', 'User.Read'
);

2. Authenticate with PKCE

var PKCESession := TOAuth2PKCE.Generate;
var OAuthClient := TOAuth2Client.Create(Config);
var AuthUrl := OAuthClient.GenerateAuthorizationUrl(PKCESession);
// Open AuthUrl in browser, handle callback to receive authorization codevar Tokens := OAuthClient.ExchangeCodeForToken(Code, PKCESession.CodeVerifier);

3. Use Graph Clients

var Mail: IMailClient := TMailClient.Create(Tokens.AccessToken);
var SearchResult := Mail.SearchMessages('*', '', 10, 0);
forvar Msg in SearchResult.Messages do
WriteLn(Msg.Subject, ' - ', Msg.From.Address);

4. Refresh Tokens

if Tokens.IsExpiringSoon(300) thenbeginvar NewTokens := OAuthClient.RefreshAccessToken(Tokens.RefreshToken);
if NewTokens.RefreshToken.IsEmpty then
NewTokens.RefreshToken := Tokens.RefreshToken;
end;

5. Share a Single HTTP Client

All Graph clients accept an existing TGraphHttpClient, allowing you to share one connection across multiple services:

var Http := TGraphHttpClient.Create(Tokens.AccessToken);
var Mail: IMailClient := TMailClient.Create(Http);
var Calendar: ICalendarClient := TCalendarClient.Create(Http);

6. Access Shared Mailboxes

Set MailboxAddress on TGraphHttpClient to target a shared or delegated mailbox. When empty (default), endpoints use /me. When set, endpoints use /users/{address}:

var Http := TGraphHttpClient.Create(Tokens.AccessToken);
Http.MailboxAddress := 'projects@company.com';
var Mail: IMailClient := TMailClient.Create(Http);
var Messages := Mail.SearchMessages('*', '', 10, 0);

This requires the Mail.Read.Shared and/or Mail.Send.Shared delegated permissions in your Azure AD app registration.

7. Add Custom Internet Message Headers

CreateDraft has an overload that takes custom headers. They are written to the message as internetMessageHeaders and travel with it when the draft is sent:

var Draft := Mail.CreateDraft('Subject', 'Body', ['recipient@company.com'], [], [], False,
[TMailHeader.Create('x-example-id', '42')]);
Mail.SendDraft(Draft.Id);

Microsoft Graph requires a custom header name to start with x-, and accepts at most five custom headers per message. The library validates the headers before sending anything and raises EInvalidMailHeaderException with a readable message when a rule is broken:

RuleRejected example
At most five custom headers per messagesix headers
The name must not be empty''
The name must start with x- (case insensitive)Example-Id
The name may contain printable ASCII only, and no :x-example-id:42, x-example-id
The value must not contain control characters or line separators42<CR><LF>x-injected: yes
The same name must not be supplied twice (case insensitive)x-example-id and X-Example-Id

Names are sent exactly as supplied — the library does not change their casing.

Graph accepts internetMessageHeaders only when a message is created, so UpdateDraft does not offer this parameter.

Two things to know about the receiving side. Exchange Online maps a custom header name to a named property on first use, and does not store the value on that very first message — only later messages carrying the same header name keep their value. A transport rule or the header firewall can also strip custom headers in transit.

Project Structure

Source/
OAuth2/
MSGraph.OAuth2.Types.pas -Config records, token response, PKCE session, exceptions
MSGraph.OAuth2.PKCE.pas -PKCE code_verifier + code_challenge generation
MSGraph.OAuth2.Client.pas -OAuth2 flow: auth URL, token exchange, refresh
MSGraph.OAuth2.TokenStore.pas -Thread-safe in-memory token + PKCE storage
Graph/
MSGraph.Graph.Http.pas -Graph API HTTP client with error handling
MSGraph.Graph.JsonHelper.pas -JSON parsing utilities (TGraphJson)
MSGraph.Graph.Mail.Types.pas -Mail record types (TMailMessage, TMailFolder, etc.)
MSGraph.Graph.Mail.Interfaces.pas -IMailClient interface
MSGraph.Graph.Mail.pas -TMailClient implementation
MSGraph.Graph.Calendar.Types.pas -Calendar record types (TCalendarEvent, TAttendee, etc.)
MSGraph.Graph.Calendar.Interfaces.pas -ICalendarClient interface
MSGraph.Graph.Calendar.pas -TCalendarClient implementation
MSGraph.Graph.Contacts.Types.pas -Contact record types (TContact, TPostalAddress, etc.)
MSGraph.Graph.Contacts.Interfaces.pas -IContactsClient interface
MSGraph.Graph.Contacts.pas -TContactsClient implementation
MSGraph.Graph.SharePoint.Types.pas -SharePoint record types (TSite, TDriveItem)
MSGraph.Graph.SharePoint.Interfaces.pas -ISharePointClient interface
MSGraph.Graph.SharePoint.pas -TSharePointClient implementation
Examples/
Microsoft365Demo.dpr -Console demo with interactive menu
Microsoft365Demo.App.pas -Demo application logic
Microsoft365Demo.CallbackServer.pas -Indy HTTP server for OAuth callback

API Reference

Exception Hierarchy

All library exceptions inherit from EMSGraphException:

ExceptionRaised by
EMSGraphExceptionBase exception for all Microsoft365-4D errors
EOAuth2ExceptionToken exchange failures, invalid responses
EGraphApiExceptionGraph API HTTP errors, missing access token
ETokenStoreExceptionMissing tokens, expired PKCE sessions
EInvalidMailHeaderExceptionInvalid custom mail header supplied by the caller
EDeltaLinkExpiredExceptionAn expired delta link, so a full resynchronisation is needed

TMailClient

MethodDescription
SearchMessages(Query, FolderId, Top, Skip)Search or list messages
GetMessage(MessageId)Get full message by ID
GetMessageAttachments(MessageId)List attachments
GetAttachmentContent(MessageId, AttachmentId)Get attachment content
CreateDraft(Subject, Body, To, Cc, Bcc, IsHtml)Create draft
CreateDraft(Subject, Body, To, Cc, Bcc, IsHtml, Headers)Create draft with custom internet message headers
UpdateDraft(MessageId, Subject, Body, To, Cc, Bcc, IsHtml)Update existing draft
SendDraft(MessageId)Send a draft message
DeleteDraft(MessageId)Delete a draft
MoveMessage(MessageId, FolderId)Move message to folder
ListMailFolders(ParentFolderId)List mail folders
GetMailboxSignatureGet HTML signature

TCalendarClient

MethodDescription
ListEvents(Start, End, Top, Timezone)List calendar events in range
GetEvent(EventId)Get event details
CreateEvent(Subject, Start, End, Location, Body, Attendees, IsAllDay)Create event
UpdateEvent(EventId, Subject, Start, End, Location, Body, Attendees, IsAllDay)Update event
DeleteEvent(EventId)Delete event
GetScheduleAvailability(Schedules, Start, End, Timezone)Check availability

TContactsClient

MethodDescription
SearchContacts(Query, Top)Search or list contacts
GetContact(ContactId)Get contact details
CreateContact(GivenName, Surname, Email, Phone, Company, JobTitle)Create contact
UpdateContact(ContactId, GivenName, Surname, Email, Phone, Company, JobTitle)Update contact
DeleteContact(ContactId)Delete contact

TSharePointClient

MethodDescription
ListSites(Query, Top)Search SharePoint sites
GetSite(SiteId)Get site details
ListDriveItems(SiteId, FolderId, Top)List items in drive/folder
SearchDriveItems(SiteId, Query, Top)Search drive items
GetDriveItemContent(SiteId, ItemId)Get item details + download URL

Demo Application

The Examples/ folder contains a console application demonstrating the full OAuth2 flow and all Graph API operations.

Running the Demo

Microsoft365Demo.exe --client-id "your-id" --client-secret "your-secret" --tenant-id "your-tenant" --redirect-uri "http://localhost:8080/oauth/callback"

All parameters can also be provided interactively when omitted. Available options:

ParameterDescriptionDefault
--client-idAzure AD application ID(prompted)
--client-secretAzure AD client secret(prompted)
--tenant-idAzure AD tenant ID(prompted)
--redirect-uriOAuth2 redirect URIhttp://localhost:8080/oauth/callback
--portLocal callback server port8080

Demo Menu

The demo provides an interactive menu with the following options:

  1. Authenticate (opens browser for Microsoft login)
  2. List messages
  3. Read message by ID
  4. Send email (create draft + send)
  5. List mail folders
  6. List calendar events
  7. Create calendar event
  8. Search contacts
  9. List SharePoint sites
  10. Refresh token manually

Azure AD App Registration

  1. Go to Azure Portal > Microsoft Entra ID > App registrations > New registration
  2. Set Redirect URI to your callback URL (Web platform), e.g. http://localhost:8080/oauth/callback
  3. Create a Client secret under Certificates & secrets
  4. Add API permissions (Microsoft Graph, Delegated):
PermissionDescription
openidSign-in
profileUser profile
offline_accessRefresh tokens
Mail.ReadRead mail
Mail.ReadWriteCreate/edit drafts
Mail.SendSend mail
MailboxSettings.ReadRead mailbox signature
Calendars.ReadWriteCalendar access
Contacts.ReadWriteContacts access
Sites.Read.AllSharePoint read access
User.ReadUser info
Mail.Read.SharedRead shared/delegated mailboxes
Mail.Send.SharedSend from shared/delegated mailboxes
  1. Click Grant admin consent if you have admin rights

Token Storage

The included TTokenStore stores tokens in-memory only and is intended for demo/development use. For production:

  • Persist tokens to a database, file, or OS-level credential store
  • Encrypt refresh tokens and access tokens before storage
  • Implement your own storage by subclassing or replacing TTokenStore

License

MIT License. See LICENSE for details.

Commercial Support

This library is MIT licensed and free to use. For companies that depend on it commercially we offer support and maintenance agreements with guaranteed response times, and sponsored development of features you need. Contact us at gdksoftware.com/contact-us or open an issue to get in touch.

About GDK Software

Microsoft365-4D is developed by GDK Software, a Delphi-focused software company building developer tools, MCP integrations, and enterprise applications.

About

Delphi library for Microsoft 365 integration. OAuth2 with PKCE, Mail, Calendar, Contacts, and SharePoint via Microsoft Graph API. No external dependencies.

Resources

Stars

35 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Microsoft365-4D

Delphi VersionPlatformLicense

Pure Delphi library for Microsoft Graph API integration. Provides OAuth2 authentication with PKCE and typed clients for Mail, Calendar, Contacts, and SharePoint. No external dependencies beyond the Delphi RTL.

Table of Contents

Features

  • OAuth2 + PKCE authentication flow for Microsoft identity platform
  • Mail -search, read, draft, send, delete, move messages, list folders, attachments
  • Calendar -list, create, update, delete events, check schedule availability
  • Contacts -search, create, update, delete contacts
  • SharePoint -browse sites, list/search drive items, get file content
  • Zero dependencies -uses only System.Net.HttpClient (Delphi RTL)
  • Pluggable logging -TLogProc callback, no global logger
  • Shared HTTP client -all Graph clients can share a single TGraphHttpClient
  • Shared mailbox support -access shared/delegated mailboxes via MailboxAddress property
  • Typed responses -all API calls return strongly-typed records (TMailMessage, TCalendarEvent, etc.)
  • Interface-based -all clients implement interfaces (IMailClient, ICalendarClient, etc.) for dependency injection

Requirements

  • Delphi 11 Alexandria or later (RAD Studio 11.x+)
  • Azure AD App Registration with appropriate API permissions

Installation

Using as a Library

Add the Source/OAuth2 and Source/Graph directories to your project's search path:

Source\OAuth2;Source\Graph

Then add the units you need to your uses clause:

uses
MSGraph.OAuth2.Types,
MSGraph.OAuth2.PKCE,
MSGraph.OAuth2.Client,
MSGraph.OAuth2.TokenStore,
MSGraph.Graph.Http,
MSGraph.Graph.Mail.Interfaces,
MSGraph.Graph.Mail,
MSGraph.Graph.Calendar.Interfaces,
MSGraph.Graph.Calendar,
MSGraph.Graph.Contacts.Interfaces,
MSGraph.Graph.Contacts,
MSGraph.Graph.SharePoint.Interfaces,
MSGraph.Graph.SharePoint;

Quick Start

1. Configure OAuth2

var Config: TOAuth2Config;
Config.ClientId := 'your-client-id';
Config.ClientSecret := 'your-client-secret';
Config.TenantId := 'your-tenant-id';
Config.RedirectUri := 'http://localhost:8080/oauth/callback';
Config.Scopes := TArray<string>.Create(
'openid', 'offline_access',
'Mail.Read', 'Mail.ReadWrite', 'Mail.Send',
'Calendars.ReadWrite', 'Contacts.ReadWrite',
'Sites.Read.All', 'User.Read'
);

2. Authenticate with PKCE

var PKCESession := TOAuth2PKCE.Generate;
var OAuthClient := TOAuth2Client.Create(Config);
var AuthUrl := OAuthClient.GenerateAuthorizationUrl(PKCESession);
// Open AuthUrl in browser, handle callback to receive authorization codevar Tokens := OAuthClient.ExchangeCodeForToken(Code, PKCESession.CodeVerifier);

3. Use Graph Clients

var Mail: IMailClient := TMailClient.Create(Tokens.AccessToken);
var SearchResult := Mail.SearchMessages('*', '', 10, 0);
forvar Msg in SearchResult.Messages do
WriteLn(Msg.Subject, ' - ', Msg.From.Address);

4. Refresh Tokens

if Tokens.IsExpiringSoon(300) thenbeginvar NewTokens := OAuthClient.RefreshAccessToken(Tokens.RefreshToken);
if NewTokens.RefreshToken.IsEmpty then
NewTokens.RefreshToken := Tokens.RefreshToken;
end;

5. Share a Single HTTP Client

All Graph clients accept an existing TGraphHttpClient, allowing you to share one connection across multiple services:

var Http := TGraphHttpClient.Create(Tokens.AccessToken);
var Mail: IMailClient := TMailClient.Create(Http);
var Calendar: ICalendarClient := TCalendarClient.Create(Http);

6. Access Shared Mailboxes

Set MailboxAddress on TGraphHttpClient to target a shared or delegated mailbox. When empty (default), endpoints use /me. When set, endpoints use /users/{address}:

var Http := TGraphHttpClient.Create(Tokens.AccessToken);
Http.MailboxAddress := 'projects@company.com';
var Mail: IMailClient := TMailClient.Create(Http);
var Messages := Mail.SearchMessages('*', '', 10, 0);

This requires the Mail.Read.Shared and/or Mail.Send.Shared delegated permissions in your Azure AD app registration.

7. Add Custom Internet Message Headers

CreateDraft has an overload that takes custom headers. They are written to the message as internetMessageHeaders and travel with it when the draft is sent:

var Draft := Mail.CreateDraft('Subject', 'Body', ['recipient@company.com'], [], [], False,
[TMailHeader.Create('x-example-id', '42')]);
Mail.SendDraft(Draft.Id);

Microsoft Graph requires a custom header name to start with x-, and accepts at most five custom headers per message. The library validates the headers before sending anything and raises EInvalidMailHeaderException with a readable message when a rule is broken:

RuleRejected example
At most five custom headers per messagesix headers
The name must not be empty''
The name must start with x- (case insensitive)Example-Id
The name may contain printable ASCII only, and no :x-example-id:42, x-example-id
The value must not contain control characters or line separators42<CR><LF>x-injected: yes
The same name must not be supplied twice (case insensitive)x-example-id and X-Example-Id

Names are sent exactly as supplied — the library does not change their casing.

Graph accepts internetMessageHeaders only when a message is created, so UpdateDraft does not offer this parameter.

Two things to know about the receiving side. Exchange Online maps a custom header name to a named property on first use, and does not store the value on that very first message — only later messages carrying the same header name keep their value. A transport rule or the header firewall can also strip custom headers in transit.

Project Structure

Source/
OAuth2/
MSGraph.OAuth2.Types.pas -Config records, token response, PKCE session, exceptions
MSGraph.OAuth2.PKCE.pas -PKCE code_verifier + code_challenge generation
MSGraph.OAuth2.Client.pas -OAuth2 flow: auth URL, token exchange, refresh
MSGraph.OAuth2.TokenStore.pas -Thread-safe in-memory token + PKCE storage
Graph/
MSGraph.Graph.Http.pas -Graph API HTTP client with error handling
MSGraph.Graph.JsonHelper.pas -JSON parsing utilities (TGraphJson)
MSGraph.Graph.Mail.Types.pas -Mail record types (TMailMessage, TMailFolder, etc.)
MSGraph.Graph.Mail.Interfaces.pas -IMailClient interface
MSGraph.Graph.Mail.pas -TMailClient implementation
MSGraph.Graph.Calendar.Types.pas -Calendar record types (TCalendarEvent, TAttendee, etc.)
MSGraph.Graph.Calendar.Interfaces.pas -ICalendarClient interface
MSGraph.Graph.Calendar.pas -TCalendarClient implementation
MSGraph.Graph.Contacts.Types.pas -Contact record types (TContact, TPostalAddress, etc.)
MSGraph.Graph.Contacts.Interfaces.pas -IContactsClient interface
MSGraph.Graph.Contacts.pas -TContactsClient implementation
MSGraph.Graph.SharePoint.Types.pas -SharePoint record types (TSite, TDriveItem)
MSGraph.Graph.SharePoint.Interfaces.pas -ISharePointClient interface
MSGraph.Graph.SharePoint.pas -TSharePointClient implementation
Examples/
Microsoft365Demo.dpr -Console demo with interactive menu
Microsoft365Demo.App.pas -Demo application logic
Microsoft365Demo.CallbackServer.pas -Indy HTTP server for OAuth callback

API Reference

Exception Hierarchy

All library exceptions inherit from EMSGraphException:

ExceptionRaised by
EMSGraphExceptionBase exception for all Microsoft365-4D errors
EOAuth2ExceptionToken exchange failures, invalid responses
EGraphApiExceptionGraph API HTTP errors, missing access token
ETokenStoreExceptionMissing tokens, expired PKCE sessions
EInvalidMailHeaderExceptionInvalid custom mail header supplied by the caller
EDeltaLinkExpiredExceptionAn expired delta link, so a full resynchronisation is needed

TMailClient

MethodDescription
SearchMessages(Query, FolderId, Top, Skip)Search or list messages
GetMessage(MessageId)Get full message by ID
GetMessageAttachments(MessageId)List attachments
GetAttachmentContent(MessageId, AttachmentId)Get attachment content
CreateDraft(Subject, Body, To, Cc, Bcc, IsHtml)Create draft
CreateDraft(Subject, Body, To, Cc, Bcc, IsHtml, Headers)Create draft with custom internet message headers
UpdateDraft(MessageId, Subject, Body, To, Cc, Bcc, IsHtml)Update existing draft
SendDraft(MessageId)Send a draft message
DeleteDraft(MessageId)Delete a draft
MoveMessage(MessageId, FolderId)Move message to folder
ListMailFolders(ParentFolderId)List mail folders
GetMailboxSignatureGet HTML signature

TCalendarClient

MethodDescription
ListEvents(Start, End, Top, Timezone)List calendar events in range
GetEvent(EventId)Get event details
CreateEvent(Subject, Start, End, Location, Body, Attendees, IsAllDay)Create event
UpdateEvent(EventId, Subject, Start, End, Location, Body, Attendees, IsAllDay)Update event
DeleteEvent(EventId)Delete event
GetScheduleAvailability(Schedules, Start, End, Timezone)Check availability

TContactsClient

MethodDescription
SearchContacts(Query, Top)Search or list contacts
GetContact(ContactId)Get contact details
CreateContact(GivenName, Surname, Email, Phone, Company, JobTitle)Create contact
UpdateContact(ContactId, GivenName, Surname, Email, Phone, Company, JobTitle)Update contact
DeleteContact(ContactId)Delete contact

TSharePointClient

MethodDescription
ListSites(Query, Top)Search SharePoint sites
GetSite(SiteId)Get site details
ListDriveItems(SiteId, FolderId, Top)List items in drive/folder
SearchDriveItems(SiteId, Query, Top)Search drive items
GetDriveItemContent(SiteId, ItemId)Get item details + download URL

Demo Application

The Examples/ folder contains a console application demonstrating the full OAuth2 flow and all Graph API operations.

Running the Demo

Microsoft365Demo.exe --client-id "your-id" --client-secret "your-secret" --tenant-id "your-tenant" --redirect-uri "http://localhost:8080/oauth/callback"

All parameters can also be provided interactively when omitted. Available options:

ParameterDescriptionDefault
--client-idAzure AD application ID(prompted)
--client-secretAzure AD client secret(prompted)
--tenant-idAzure AD tenant ID(prompted)
--redirect-uriOAuth2 redirect URIhttp://localhost:8080/oauth/callback
--portLocal callback server port8080

Demo Menu

The demo provides an interactive menu with the following options:

  1. Authenticate (opens browser for Microsoft login)
  2. List messages
  3. Read message by ID
  4. Send email (create draft + send)
  5. List mail folders
  6. List calendar events
  7. Create calendar event
  8. Search contacts
  9. List SharePoint sites
  10. Refresh token manually

Azure AD App Registration

  1. Go to Azure Portal > Microsoft Entra ID > App registrations > New registration
  2. Set Redirect URI to your callback URL (Web platform), e.g. http://localhost:8080/oauth/callback
  3. Create a Client secret under Certificates & secrets
  4. Add API permissions (Microsoft Graph, Delegated):
PermissionDescription
openidSign-in
profileUser profile
offline_accessRefresh tokens
Mail.ReadRead mail
Mail.ReadWriteCreate/edit drafts
Mail.SendSend mail
MailboxSettings.ReadRead mailbox signature
Calendars.ReadWriteCalendar access
Contacts.ReadWriteContacts access
Sites.Read.AllSharePoint read access
User.ReadUser info
Mail.Read.SharedRead shared/delegated mailboxes
Mail.Send.SharedSend from shared/delegated mailboxes
  1. Click Grant admin consent if you have admin rights

Token Storage

The included TTokenStore stores tokens in-memory only and is intended for demo/development use. For production:

  • Persist tokens to a database, file, or OS-level credential store
  • Encrypt refresh tokens and access tokens before storage
  • Implement your own storage by subclassing or replacing TTokenStore

License

MIT License. See LICENSE for details.

Commercial Support

This library is MIT licensed and free to use. For companies that depend on it commercially we offer support and maintenance agreements with guaranteed response times, and sponsored development of features you need. Contact us at gdksoftware.com/contact-us or open an issue to get in touch.

About GDK Software

Microsoft365-4D is developed by GDK Software, a Delphi-focused software company building developer tools, MCP integrations, and enterprise applications.

About

Delphi library for Microsoft 365 integration. OAuth2 with PKCE, Mail, Calendar, Contacts, and SharePoint via Microsoft Graph API. No external dependencies.

Resources

Stars

35 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Microsoft365-4D

Delphi VersionPlatformLicense

Pure Delphi library for Microsoft Graph API integration. Provides OAuth2 authentication with PKCE and typed clients for Mail, Calendar, Contacts, and SharePoint. No external dependencies beyond the Delphi RTL.

Table of Contents

Features

  • OAuth2 + PKCE authentication flow for Microsoft identity platform
  • Mail -search, read, draft, send, delete, move messages, list folders, attachments
  • Calendar -list, create, update, delete events, check schedule availability
  • Contacts -search, create, update, delete contacts
  • SharePoint -browse sites, list/search drive items, get file content
  • Zero dependencies -uses only System.Net.HttpClient (Delphi RTL)
  • Pluggable logging -TLogProc callback, no global logger
  • Shared HTTP client -all Graph clients can share a single TGraphHttpClient
  • Shared mailbox support -access shared/delegated mailboxes via MailboxAddress property
  • Typed responses -all API calls return strongly-typed records (TMailMessage, TCalendarEvent, etc.)
  • Interface-based -all clients implement interfaces (IMailClient, ICalendarClient, etc.) for dependency injection

Requirements

  • Delphi 11 Alexandria or later (RAD Studio 11.x+)
  • Azure AD App Registration with appropriate API permissions

Installation

Using as a Library

Add the Source/OAuth2 and Source/Graph directories to your project's search path:

Source\OAuth2;Source\Graph

Then add the units you need to your uses clause:

uses
MSGraph.OAuth2.Types,
MSGraph.OAuth2.PKCE,
MSGraph.OAuth2.Client,
MSGraph.OAuth2.TokenStore,
MSGraph.Graph.Http,
MSGraph.Graph.Mail.Interfaces,
MSGraph.Graph.Mail,
MSGraph.Graph.Calendar.Interfaces,
MSGraph.Graph.Calendar,
MSGraph.Graph.Contacts.Interfaces,
MSGraph.Graph.Contacts,
MSGraph.Graph.SharePoint.Interfaces,
MSGraph.Graph.SharePoint;

Quick Start

1. Configure OAuth2

var Config: TOAuth2Config;
Config.ClientId := 'your-client-id';
Config.ClientSecret := 'your-client-secret';
Config.TenantId := 'your-tenant-id';
Config.RedirectUri := 'http://localhost:8080/oauth/callback';
Config.Scopes := TArray<string>.Create(
'openid', 'offline_access',
'Mail.Read', 'Mail.ReadWrite', 'Mail.Send',
'Calendars.ReadWrite', 'Contacts.ReadWrite',
'Sites.Read.All', 'User.Read'
);

2. Authenticate with PKCE

var PKCESession := TOAuth2PKCE.Generate;
var OAuthClient := TOAuth2Client.Create(Config);
var AuthUrl := OAuthClient.GenerateAuthorizationUrl(PKCESession);
// Open AuthUrl in browser, handle callback to receive authorization codevar Tokens := OAuthClient.ExchangeCodeForToken(Code, PKCESession.CodeVerifier);

3. Use Graph Clients

var Mail: IMailClient := TMailClient.Create(Tokens.AccessToken);
var SearchResult := Mail.SearchMessages('*', '', 10, 0);
forvar Msg in SearchResult.Messages do
WriteLn(Msg.Subject, ' - ', Msg.From.Address);

4. Refresh Tokens

if Tokens.IsExpiringSoon(300) thenbeginvar NewTokens := OAuthClient.RefreshAccessToken(Tokens.RefreshToken);
if NewTokens.RefreshToken.IsEmpty then
NewTokens.RefreshToken := Tokens.RefreshToken;
end;

5. Share a Single HTTP Client

All Graph clients accept an existing TGraphHttpClient, allowing you to share one connection across multiple services:

var Http := TGraphHttpClient.Create(Tokens.AccessToken);
var Mail: IMailClient := TMailClient.Create(Http);
var Calendar: ICalendarClient := TCalendarClient.Create(Http);

6. Access Shared Mailboxes

Set MailboxAddress on TGraphHttpClient to target a shared or delegated mailbox. When empty (default), endpoints use /me. When set, endpoints use /users/{address}:

var Http := TGraphHttpClient.Create(Tokens.AccessToken);
Http.MailboxAddress := 'projects@company.com';
var Mail: IMailClient := TMailClient.Create(Http);
var Messages := Mail.SearchMessages('*', '', 10, 0);

This requires the Mail.Read.Shared and/or Mail.Send.Shared delegated permissions in your Azure AD app registration.

7. Add Custom Internet Message Headers

CreateDraft has an overload that takes custom headers. They are written to the message as internetMessageHeaders and travel with it when the draft is sent:

var Draft := Mail.CreateDraft('Subject', 'Body', ['recipient@company.com'], [], [], False,
[TMailHeader.Create('x-example-id', '42')]);
Mail.SendDraft(Draft.Id);

Microsoft Graph requires a custom header name to start with x-, and accepts at most five custom headers per message. The library validates the headers before sending anything and raises EInvalidMailHeaderException with a readable message when a rule is broken:

RuleRejected example
At most five custom headers per messagesix headers
The name must not be empty''
The name must start with x- (case insensitive)Example-Id
The name may contain printable ASCII only, and no :x-example-id:42, x-example-id
The value must not contain control characters or line separators42<CR><LF>x-injected: yes
The same name must not be supplied twice (case insensitive)x-example-id and X-Example-Id

Names are sent exactly as supplied — the library does not change their casing.

Graph accepts internetMessageHeaders only when a message is created, so UpdateDraft does not offer this parameter.

Two things to know about the receiving side. Exchange Online maps a custom header name to a named property on first use, and does not store the value on that very first message — only later messages carrying the same header name keep their value. A transport rule or the header firewall can also strip custom headers in transit.

Project Structure

Source/
OAuth2/
MSGraph.OAuth2.Types.pas -Config records, token response, PKCE session, exceptions
MSGraph.OAuth2.PKCE.pas -PKCE code_verifier + code_challenge generation
MSGraph.OAuth2.Client.pas -OAuth2 flow: auth URL, token exchange, refresh
MSGraph.OAuth2.TokenStore.pas -Thread-safe in-memory token + PKCE storage
Graph/
MSGraph.Graph.Http.pas -Graph API HTTP client with error handling
MSGraph.Graph.JsonHelper.pas -JSON parsing utilities (TGraphJson)
MSGraph.Graph.Mail.Types.pas -Mail record types (TMailMessage, TMailFolder, etc.)
MSGraph.Graph.Mail.Interfaces.pas -IMailClient interface
MSGraph.Graph.Mail.pas -TMailClient implementation
MSGraph.Graph.Calendar.Types.pas -Calendar record types (TCalendarEvent, TAttendee, etc.)
MSGraph.Graph.Calendar.Interfaces.pas -ICalendarClient interface
MSGraph.Graph.Calendar.pas -TCalendarClient implementation
MSGraph.Graph.Contacts.Types.pas -Contact record types (TContact, TPostalAddress, etc.)
MSGraph.Graph.Contacts.Interfaces.pas -IContactsClient interface
MSGraph.Graph.Contacts.pas -TContactsClient implementation
MSGraph.Graph.SharePoint.Types.pas -SharePoint record types (TSite, TDriveItem)
MSGraph.Graph.SharePoint.Interfaces.pas -ISharePointClient interface
MSGraph.Graph.SharePoint.pas -TSharePointClient implementation
Examples/
Microsoft365Demo.dpr -Console demo with interactive menu
Microsoft365Demo.App.pas -Demo application logic
Microsoft365Demo.CallbackServer.pas -Indy HTTP server for OAuth callback

API Reference

Exception Hierarchy

All library exceptions inherit from EMSGraphException:

ExceptionRaised by
EMSGraphExceptionBase exception for all Microsoft365-4D errors
EOAuth2ExceptionToken exchange failures, invalid responses
EGraphApiExceptionGraph API HTTP errors, missing access token
ETokenStoreExceptionMissing tokens, expired PKCE sessions
EInvalidMailHeaderExceptionInvalid custom mail header supplied by the caller
EDeltaLinkExpiredExceptionAn expired delta link, so a full resynchronisation is needed

TMailClient

MethodDescription
SearchMessages(Query, FolderId, Top, Skip)Search or list messages
GetMessage(MessageId)Get full message by ID
GetMessageAttachments(MessageId)List attachments
GetAttachmentContent(MessageId, AttachmentId)Get attachment content
CreateDraft(Subject, Body, To, Cc, Bcc, IsHtml)Create draft
CreateDraft(Subject, Body, To, Cc, Bcc, IsHtml, Headers)Create draft with custom internet message headers
UpdateDraft(MessageId, Subject, Body, To, Cc, Bcc, IsHtml)Update existing draft
SendDraft(MessageId)Send a draft message
DeleteDraft(MessageId)Delete a draft
MoveMessage(MessageId, FolderId)Move message to folder
ListMailFolders(ParentFolderId)List mail folders
GetMailboxSignatureGet HTML signature

TCalendarClient

MethodDescription
ListEvents(Start, End, Top, Timezone)List calendar events in range
GetEvent(EventId)Get event details
CreateEvent(Subject, Start, End, Location, Body, Attendees, IsAllDay)Create event
UpdateEvent(EventId, Subject, Start, End, Location, Body, Attendees, IsAllDay)Update event
DeleteEvent(EventId)Delete event
GetScheduleAvailability(Schedules, Start, End, Timezone)Check availability

TContactsClient

MethodDescription
SearchContacts(Query, Top)Search or list contacts
GetContact(ContactId)Get contact details
CreateContact(GivenName, Surname, Email, Phone, Company, JobTitle)Create contact
UpdateContact(ContactId, GivenName, Surname, Email, Phone, Company, JobTitle)Update contact
DeleteContact(ContactId)Delete contact

TSharePointClient

MethodDescription
ListSites(Query, Top)Search SharePoint sites
GetSite(SiteId)Get site details
ListDriveItems(SiteId, FolderId, Top)List items in drive/folder
SearchDriveItems(SiteId, Query, Top)Search drive items
GetDriveItemContent(SiteId, ItemId)Get item details + download URL

Demo Application

The Examples/ folder contains a console application demonstrating the full OAuth2 flow and all Graph API operations.

Running the Demo

Microsoft365Demo.exe --client-id "your-id" --client-secret "your-secret" --tenant-id "your-tenant" --redirect-uri "http://localhost:8080/oauth/callback"

All parameters can also be provided interactively when omitted. Available options:

ParameterDescriptionDefault
--client-idAzure AD application ID(prompted)
--client-secretAzure AD client secret(prompted)
--tenant-idAzure AD tenant ID(prompted)
--redirect-uriOAuth2 redirect URIhttp://localhost:8080/oauth/callback
--portLocal callback server port8080

Demo Menu

The demo provides an interactive menu with the following options:

  1. Authenticate (opens browser for Microsoft login)
  2. List messages
  3. Read message by ID
  4. Send email (create draft + send)
  5. List mail folders
  6. List calendar events
  7. Create calendar event
  8. Search contacts
  9. List SharePoint sites
  10. Refresh token manually

Azure AD App Registration

  1. Go to Azure Portal > Microsoft Entra ID > App registrations > New registration
  2. Set Redirect URI to your callback URL (Web platform), e.g. http://localhost:8080/oauth/callback
  3. Create a Client secret under Certificates & secrets
  4. Add API permissions (Microsoft Graph, Delegated):
PermissionDescription
openidSign-in
profileUser profile
offline_accessRefresh tokens
Mail.ReadRead mail
Mail.ReadWriteCreate/edit drafts
Mail.SendSend mail
MailboxSettings.ReadRead mailbox signature
Calendars.ReadWriteCalendar access
Contacts.ReadWriteContacts access
Sites.Read.AllSharePoint read access
User.ReadUser info
Mail.Read.SharedRead shared/delegated mailboxes
Mail.Send.SharedSend from shared/delegated mailboxes
  1. Click Grant admin consent if you have admin rights

Token Storage

The included TTokenStore stores tokens in-memory only and is intended for demo/development use. For production:

  • Persist tokens to a database, file, or OS-level credential store
  • Encrypt refresh tokens and access tokens before storage
  • Implement your own storage by subclassing or replacing TTokenStore

License

MIT License. See LICENSE for details.

Commercial Support

This library is MIT licensed and free to use. For companies that depend on it commercially we offer support and maintenance agreements with guaranteed response times, and sponsored development of features you need. Contact us at gdksoftware.com/contact-us or open an issue to get in touch.

About GDK Software

Microsoft365-4D is developed by GDK Software, a Delphi-focused software company building developer tools, MCP integrations, and enterprise applications.

About

Delphi library for Microsoft 365 integration. OAuth2 with PKCE, Mail, Calendar, Contacts, and SharePoint via Microsoft Graph API. No external dependencies.

Resources

Stars

35 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Microsoft365-4D

Delphi VersionPlatformLicense

Pure Delphi library for Microsoft Graph API integration. Provides OAuth2 authentication with PKCE and typed clients for Mail, Calendar, Contacts, and SharePoint. No external dependencies beyond the Delphi RTL.

Table of Contents

Features

  • OAuth2 + PKCE authentication flow for Microsoft identity platform
  • Mail -search, read, draft, send, delete, move messages, list folders, attachments
  • Calendar -list, create, update, delete events, check schedule availability
  • Contacts -search, create, update, delete contacts
  • SharePoint -browse sites, list/search drive items, get file content
  • Zero dependencies -uses only System.Net.HttpClient (Delphi RTL)
  • Pluggable logging -TLogProc callback, no global logger
  • Shared HTTP client -all Graph clients can share a single TGraphHttpClient
  • Shared mailbox support -access shared/delegated mailboxes via MailboxAddress property
  • Typed responses -all API calls return strongly-typed records (TMailMessage, TCalendarEvent, etc.)
  • Interface-based -all clients implement interfaces (IMailClient, ICalendarClient, etc.) for dependency injection

Requirements

  • Delphi 11 Alexandria or later (RAD Studio 11.x+)
  • Azure AD App Registration with appropriate API permissions

Installation

Using as a Library

Add the Source/OAuth2 and Source/Graph directories to your project's search path:

Source\OAuth2;Source\Graph

Then add the units you need to your uses clause:

uses
MSGraph.OAuth2.Types,
MSGraph.OAuth2.PKCE,
MSGraph.OAuth2.Client,
MSGraph.OAuth2.TokenStore,
MSGraph.Graph.Http,
MSGraph.Graph.Mail.Interfaces,
MSGraph.Graph.Mail,
MSGraph.Graph.Calendar.Interfaces,
MSGraph.Graph.Calendar,
MSGraph.Graph.Contacts.Interfaces,
MSGraph.Graph.Contacts,
MSGraph.Graph.SharePoint.Interfaces,
MSGraph.Graph.SharePoint;

Quick Start

1. Configure OAuth2

var Config: TOAuth2Config;
Config.ClientId := 'your-client-id';
Config.ClientSecret := 'your-client-secret';
Config.TenantId := 'your-tenant-id';
Config.RedirectUri := 'http://localhost:8080/oauth/callback';
Config.Scopes := TArray<string>.Create(
'openid', 'offline_access',
'Mail.Read', 'Mail.ReadWrite', 'Mail.Send',
'Calendars.ReadWrite', 'Contacts.ReadWrite',
'Sites.Read.All', 'User.Read'
);

2. Authenticate with PKCE

var PKCESession := TOAuth2PKCE.Generate;
var OAuthClient := TOAuth2Client.Create(Config);
var AuthUrl := OAuthClient.GenerateAuthorizationUrl(PKCESession);
// Open AuthUrl in browser, handle callback to receive authorization codevar Tokens := OAuthClient.ExchangeCodeForToken(Code, PKCESession.CodeVerifier);

3. Use Graph Clients

var Mail: IMailClient := TMailClient.Create(Tokens.AccessToken);
var SearchResult := Mail.SearchMessages('*', '', 10, 0);
forvar Msg in SearchResult.Messages do
WriteLn(Msg.Subject, ' - ', Msg.From.Address);

4. Refresh Tokens

if Tokens.IsExpiringSoon(300) thenbeginvar NewTokens := OAuthClient.RefreshAccessToken(Tokens.RefreshToken);
if NewTokens.RefreshToken.IsEmpty then
NewTokens.RefreshToken := Tokens.RefreshToken;
end;

5. Share a Single HTTP Client

All Graph clients accept an existing TGraphHttpClient, allowing you to share one connection across multiple services:

var Http := TGraphHttpClient.Create(Tokens.AccessToken);
var Mail: IMailClient := TMailClient.Create(Http);
var Calendar: ICalendarClient := TCalendarClient.Create(Http);

6. Access Shared Mailboxes

Set MailboxAddress on TGraphHttpClient to target a shared or delegated mailbox. When empty (default), endpoints use /me. When set, endpoints use /users/{address}:

var Http := TGraphHttpClient.Create(Tokens.AccessToken);
Http.MailboxAddress := 'projects@company.com';
var Mail: IMailClient := TMailClient.Create(Http);
var Messages := Mail.SearchMessages('*', '', 10, 0);

This requires the Mail.Read.Shared and/or Mail.Send.Shared delegated permissions in your Azure AD app registration.

7. Add Custom Internet Message Headers

CreateDraft has an overload that takes custom headers. They are written to the message as internetMessageHeaders and travel with it when the draft is sent:

var Draft := Mail.CreateDraft('Subject', 'Body', ['recipient@company.com'], [], [], False,
[TMailHeader.Create('x-example-id', '42')]);
Mail.SendDraft(Draft.Id);

Microsoft Graph requires a custom header name to start with x-, and accepts at most five custom headers per message. The library validates the headers before sending anything and raises EInvalidMailHeaderException with a readable message when a rule is broken:

RuleRejected example
At most five custom headers per messagesix headers
The name must not be empty''
The name must start with x- (case insensitive)Example-Id
The name may contain printable ASCII only, and no :x-example-id:42, x-example-id
The value must not contain control characters or line separators42<CR><LF>x-injected: yes
The same name must not be supplied twice (case insensitive)x-example-id and X-Example-Id

Names are sent exactly as supplied — the library does not change their casing.

Graph accepts internetMessageHeaders only when a message is created, so UpdateDraft does not offer this parameter.

Two things to know about the receiving side. Exchange Online maps a custom header name to a named property on first use, and does not store the value on that very first message — only later messages carrying the same header name keep their value. A transport rule or the header firewall can also strip custom headers in transit.

Project Structure

Source/
OAuth2/
MSGraph.OAuth2.Types.pas -Config records, token response, PKCE session, exceptions
MSGraph.OAuth2.PKCE.pas -PKCE code_verifier + code_challenge generation
MSGraph.OAuth2.Client.pas -OAuth2 flow: auth URL, token exchange, refresh
MSGraph.OAuth2.TokenStore.pas -Thread-safe in-memory token + PKCE storage
Graph/
MSGraph.Graph.Http.pas -Graph API HTTP client with error handling
MSGraph.Graph.JsonHelper.pas -JSON parsing utilities (TGraphJson)
MSGraph.Graph.Mail.Types.pas -Mail record types (TMailMessage, TMailFolder, etc.)
MSGraph.Graph.Mail.Interfaces.pas -IMailClient interface
MSGraph.Graph.Mail.pas -TMailClient implementation
MSGraph.Graph.Calendar.Types.pas -Calendar record types (TCalendarEvent, TAttendee, etc.)
MSGraph.Graph.Calendar.Interfaces.pas -ICalendarClient interface
MSGraph.Graph.Calendar.pas -TCalendarClient implementation
MSGraph.Graph.Contacts.Types.pas -Contact record types (TContact, TPostalAddress, etc.)
MSGraph.Graph.Contacts.Interfaces.pas -IContactsClient interface
MSGraph.Graph.Contacts.pas -TContactsClient implementation
MSGraph.Graph.SharePoint.Types.pas -SharePoint record types (TSite, TDriveItem)
MSGraph.Graph.SharePoint.Interfaces.pas -ISharePointClient interface
MSGraph.Graph.SharePoint.pas -TSharePointClient implementation
Examples/
Microsoft365Demo.dpr -Console demo with interactive menu
Microsoft365Demo.App.pas -Demo application logic
Microsoft365Demo.CallbackServer.pas -Indy HTTP server for OAuth callback

API Reference

Exception Hierarchy

All library exceptions inherit from EMSGraphException:

ExceptionRaised by
EMSGraphExceptionBase exception for all Microsoft365-4D errors
EOAuth2ExceptionToken exchange failures, invalid responses
EGraphApiExceptionGraph API HTTP errors, missing access token
ETokenStoreExceptionMissing tokens, expired PKCE sessions
EInvalidMailHeaderExceptionInvalid custom mail header supplied by the caller
EDeltaLinkExpiredExceptionAn expired delta link, so a full resynchronisation is needed

TMailClient

MethodDescription
SearchMessages(Query, FolderId, Top, Skip)Search or list messages
GetMessage(MessageId)Get full message by ID
GetMessageAttachments(MessageId)List attachments
GetAttachmentContent(MessageId, AttachmentId)Get attachment content
CreateDraft(Subject, Body, To, Cc, Bcc, IsHtml)Create draft
CreateDraft(Subject, Body, To, Cc, Bcc, IsHtml, Headers)Create draft with custom internet message headers
UpdateDraft(MessageId, Subject, Body, To, Cc, Bcc, IsHtml)Update existing draft
SendDraft(MessageId)Send a draft message
DeleteDraft(MessageId)Delete a draft
MoveMessage(MessageId, FolderId)Move message to folder
ListMailFolders(ParentFolderId)List mail folders
GetMailboxSignatureGet HTML signature

TCalendarClient

MethodDescription
ListEvents(Start, End, Top, Timezone)List calendar events in range
GetEvent(EventId)Get event details
CreateEvent(Subject, Start, End, Location, Body, Attendees, IsAllDay)Create event
UpdateEvent(EventId, Subject, Start, End, Location, Body, Attendees, IsAllDay)Update event
DeleteEvent(EventId)Delete event
GetScheduleAvailability(Schedules, Start, End, Timezone)Check availability

TContactsClient

MethodDescription
SearchContacts(Query, Top)Search or list contacts
GetContact(ContactId)Get contact details
CreateContact(GivenName, Surname, Email, Phone, Company, JobTitle)Create contact
UpdateContact(ContactId, GivenName, Surname, Email, Phone, Company, JobTitle)Update contact
DeleteContact(ContactId)Delete contact

TSharePointClient

MethodDescription
ListSites(Query, Top)Search SharePoint sites
GetSite(SiteId)Get site details
ListDriveItems(SiteId, FolderId, Top)List items in drive/folder
SearchDriveItems(SiteId, Query, Top)Search drive items
GetDriveItemContent(SiteId, ItemId)Get item details + download URL

Demo Application

The Examples/ folder contains a console application demonstrating the full OAuth2 flow and all Graph API operations.

Running the Demo

Microsoft365Demo.exe --client-id "your-id" --client-secret "your-secret" --tenant-id "your-tenant" --redirect-uri "http://localhost:8080/oauth/callback"

All parameters can also be provided interactively when omitted. Available options:

ParameterDescriptionDefault
--client-idAzure AD application ID(prompted)
--client-secretAzure AD client secret(prompted)
--tenant-idAzure AD tenant ID(prompted)
--redirect-uriOAuth2 redirect URIhttp://localhost:8080/oauth/callback
--portLocal callback server port8080

Demo Menu

The demo provides an interactive menu with the following options:

  1. Authenticate (opens browser for Microsoft login)
  2. List messages
  3. Read message by ID
  4. Send email (create draft + send)
  5. List mail folders
  6. List calendar events
  7. Create calendar event
  8. Search contacts
  9. List SharePoint sites
  10. Refresh token manually

Azure AD App Registration

  1. Go to Azure Portal > Microsoft Entra ID > App registrations > New registration
  2. Set Redirect URI to your callback URL (Web platform), e.g. http://localhost:8080/oauth/callback
  3. Create a Client secret under Certificates & secrets
  4. Add API permissions (Microsoft Graph, Delegated):
PermissionDescription
openidSign-in
profileUser profile
offline_accessRefresh tokens
Mail.ReadRead mail
Mail.ReadWriteCreate/edit drafts
Mail.SendSend mail
MailboxSettings.ReadRead mailbox signature
Calendars.ReadWriteCalendar access
Contacts.ReadWriteContacts access
Sites.Read.AllSharePoint read access
User.ReadUser info
Mail.Read.SharedRead shared/delegated mailboxes
Mail.Send.SharedSend from shared/delegated mailboxes
  1. Click Grant admin consent if you have admin rights

Token Storage

The included TTokenStore stores tokens in-memory only and is intended for demo/development use. For production:

  • Persist tokens to a database, file, or OS-level credential store
  • Encrypt refresh tokens and access tokens before storage
  • Implement your own storage by subclassing or replacing TTokenStore

License

MIT License. See LICENSE for details.

Commercial Support

This library is MIT licensed and free to use. For companies that depend on it commercially we offer support and maintenance agreements with guaranteed response times, and sponsored development of features you need. Contact us at gdksoftware.com/contact-us or open an issue to get in touch.

About GDK Software

Microsoft365-4D is developed by GDK Software, a Delphi-focused software company building developer tools, MCP integrations, and enterprise applications.

About

Delphi library for Microsoft 365 integration. OAuth2 with PKCE, Mail, Calendar, Contacts, and SharePoint via Microsoft Graph API. No external dependencies.

Resources

Stars

35 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages