Skip to main content

Microsoft 365 Connectors

Seven Microsoft 365 connectors run locally through Microsoft Graph: Office 365 Outlook, Office 365 Users, Office 365 Groups, Microsoft Teams, Word Online (Business), Excel Online (Business) and OneDrive for Business. They all take a delegated Microsoft Graph token and act as the signed-in user.

These connectors let a flow run end to end on your machine, but they are thinner emulations than SharePoint and Dataverse: their outputs are mostly Microsoft Graph's own objects, which do not always match what the cloud connector returns. When a later step reads specific fields, check the local output in the trace, or mock the action with the shape you expect.

Tokens​

FlagCovers
--graph-token <token>All seven connectors.
--word-token <token>Word Online only (overrides --graph-token).
--excel-token <token>Excel Online only (overrides --graph-token).
--onedrive-token <token>OneDrive for Business only (overrides --graph-token).
--authOne Graph token for all seven, with the permissions the flow's operations need.
# Automatic: signs in once, then renews silently
flowforger run flow.ff.ts --auth

# Explicit token
az account get-access-token --resource https://graph.microsoft.com --query accessToken -o tsv
flowforger run flow.ff.ts --graph-token <token>

All tokens are for https://graph.microsoft.com. An explicit flag wins over --auth for the connectors it covers, and those connectors are left out of the --auth sign-in.

With --auth, the CLI looks at every Microsoft 365 action in the flow and requests only the permissions those operations need (table below). Run flowforger scopes flow.ff.ts to see the list for one flow. An operation the scope map does not know falls back to User.Read (User.Read.All for Office 365 Users). HttpRequest actions are not inspected: add what they call to auth.additionalScopes.graph in flowforger.config.json.

{
"auth": {
"clientId": "<client-id>",
"tenantId": "<tenant-id>",
"additionalScopes": {
"graph": ["Sites.ReadWrite.All"]
}
}
}

Word, Excel and OneDrive request Files.ReadWrite, which covers the signed-in user's own files. For templates and workbooks in a SharePoint library, add a broader Graph permission such as Sites.ReadWrite.All this way, and to the app registration.

Permissions​

All permissions are delegated Microsoft Graph permissions (App ID 00000003-0000-0000-c000-000000000000). Add them to your app registration (see App registration) and grant admin consent. flowforger scopes --all prints the full set:

ConnectorPermissions
Office 365 OutlookMail.Read, Mail.ReadWrite, Mail.Send, Calendars.Read, Calendars.ReadWrite, Contacts.Read, Contacts.ReadWrite, User.Read
Office 365 UsersUser.Read, User.Read.All, User.ReadWrite, People.Read, Sites.Read.All
Office 365 GroupsGroup.Read.All, Group.ReadWrite.All, GroupMember.Read.All, GroupMember.ReadWrite.All, User.Read
Microsoft TeamsTeam.ReadBasic.All, Team.Create, TeamMember.ReadWrite.All, Channel.ReadBasic.All, Channel.Create, ChannelMessage.Read.All, ChannelMessage.Send, Chat.Create, Chat.Read, Chat.ReadWrite, ChatMember.Read, TeamsActivity.Send, TeamworkTag.ReadWrite, OnlineMeetings.ReadWrite, Calendars.ReadWrite, User.Read, User.Read.All
Word Online (Business)Files.ReadWrite
Excel Online (Business)Files.ReadWrite
OneDrive for BusinessFiles.ReadWrite

Entra ID consents per permission, so add both the Read and ReadWrite variants where both are listed: a read-only flow requests the narrower one. The per-operation mapping is in each connector's section below.

Operation names​

Call ctx.connectors.<namespace>.<Operation>(name, params, connectionReferenceName?). The tables list the operation names the local connector accepts. A local alias (the "Local aliases" column) is written to the deployed flow as its designer operation id, with its parameters renamed to the designer's keys where they differ; a designer id is kept as written. Local names without a designer counterpart (for example Excel GetRange or Outlook GetMailFolders) are emitted unchanged and fail in the cloud, so check such an action against a flow built in the Power Automate designer, or one you pulled with flowforger pull. Outlook, Users, Groups and Teams also accept lower-camel-case aliases (sendEmail, getEmails, ...), which are not listed.

An operation the local connector does not recognise fails with "unknown operation". Several operation ids the designer writes today are in that group; they are listed per connector under Not supported locally. Mock those actions (--mock <Action>=<outputs.json>).

Connector triggers (new email, file changed, ...) are written into the compiled flow but never fire locally; pass a sample trigger body with --in. See Connector triggers.

Office 365 Outlook​

Namespace: ctx.connectors.office365. Connection reference: shared_office365.

AreaOperationsPermission
SendSendEmailV2 (SendEmail), ReplyToEmailV2, ForwardEmailV2Mail.Send
Read mailGetEmailsV2 (GetEmails), GetEmailV2 (GetEmail), GetAttachmentV2, ExportEmailV2, GetMailFoldersMail.Read
Change mailDeleteEmailV2, MoveEmailV2, MarkAsReadV3, FlagMail.ReadWrite
Read calendarGetEventsV4, GetEventV4, GetCalendars, CalendarGetTables, FindMeetingTimesV2Calendars.Read
Change calendarCreateEventV4, UpdateEventV4, DeleteEventV4, RespondToEventV2Calendars.ReadWrite
Read contactsGetContactsV2, GetContactV2, GetContactFoldersContacts.Read
Change contactsCreateContactV2, UpdateContactV2, DeleteContactV2Contacts.ReadWrite
OtherGetMyProfile, HttpRequest (a Graph request: method, uri, body, headers)User.Read
await ctx.connectors.office365.SendEmailV2('NotifyOwner', {
'emailMessage/To': 'owner@contoso.com',
'emailMessage/Subject': 'Weekly report',
'emailMessage/Body': '<p>The report is ready.</p>',
});

Local behaviour:

  • SendEmailV2 accepts the designer's emailMessage/To, /Cc, /Bcc, /Subject, /Body, /Importance, /ReplyTo, /From (shared mailbox), /IsHtml and /Attachments keys. Recipients are a ;- or ,-separated string or an array. The mail is saved to Sent Items.
  • The other operations read plain parameter names: messageId, folderPath (inbox, sentitems, ... or a folder id), top, filter, searchQuery, fetchOnlyUnread, mailboxAddress, eventId, calendarId, contactId, and so on.
  • Outputs are Microsoft Graph's objects. List operations (GetEmailsV2, GetEventsV4, GetContactsV2, GetMailFolders, ...) return a plain array, not { value: [...] }. Send, reply, forward, delete and respond return { success: true }.
  • Calendar operations work on the signed-in user's calendars only.

Designer operation ids such as GetEmailsV3, ReplyToV3, ForwardEmail_V2, DeleteEmail_V2, MoveV2, MarkAsRead_V3, GetAttachment_V2, V4CalendarPostItem, V4CalendarPatchItem and SharedMailboxSendEmailV2 run locally with the designer's flattened keys (replyParameters/Body, body/ToRecipients, item/subject, emailMessage/MailboxAddress, ...), so a pulled flow debugs as is. The typed local names (ReplyToEmailV2, MoveEmailV2, CreateEventV4, ...) are deployed as those ids with their parameters renamed to match. Triggers such as OnNewEmailV3 are emitted only.

Office 365 Users​

Namespace: ctx.connectors.office365users. Connection reference: shared_office365users.

OperationsPermission
MyProfile_V2, HttpRequestUser.Read
UserProfile_V2, Manager_V2, DirectReports_V2, SearchUserV2, UserPhoto_V2, UserPhotoMetadataUser.Read.All
RelevantPeoplePeople.Read
MyTrendingDocuments, TrendingDocumentsSites.Read.All
UpdateMyProfile, UpdateMyPhotoUser.ReadWrite
await ctx.connectors.office365users.Manager_V2('GetManager', { id: 'anna@contoso.com' });
await ctx.compose('ManagerName', ctx.body('GetManager')?.['displayName']);

Local behaviour:

  • id is a user principal name or object id. $select narrows the fields.
  • The _V2 profile operations return Graph's camelCase user (displayName, mail, jobTitle, ...). The older MyProfile, UserProfile, Manager and DirectReports return the PascalCase User shape (DisplayName, Mail, ...) with the camelCase fields kept alongside.
  • Manager_V2 for a user without a manager fails with 404 "No manager found for the specified user."
  • SearchUserV2 matches searchTerm as a prefix of the display name, given name, surname, mail, mail nickname or user principal name, and returns { value: [...] } in the PascalCase shape. With an empty searchTerm (and isSearchTermRequired not false) it returns no users.
  • UserPhoto_V2 returns { content: <base64>, contentType }, not binary content { "$content-type", "$content" }. UserPhotoMetadata returns { HasPhoto, Width, Height, ContentType, ImageFileExtension }, with HasPhoto: false when the user has no photo.
  • HttpRequest takes the designer's Uri, Method, Body, ContentType and CustomHeader1 to CustomHeader5 (Name: value).

Office 365 Groups​

Namespace: ctx.connectors.office365groups. Connection reference: shared_office365groups.

OperationsPermission
ListGroups, GetGroup, ListGroupEvents, GetGroupEventGroup.Read.All
CreateGroup, UpdateGroup, DeleteGroup, AddOwnerToGroup, RemoveOwnerFromGroup, CreateGroupEvent, UpdateGroupEvent, DeleteGroupEventGroup.ReadWrite.All
ListGroupMembers, ListGroupOwnersGroupMember.Read.All
AddMemberToGroup, RemoveMemberFromGroupGroupMember.ReadWrite.All
IsMemberOfGroup, HttpRequestUser.Read

Local behaviour:

  • Groups and members are addressed by groupId and userId.
  • List operations return Graph's { value: [...] }, so ctx.body('X')?.['value'] works as in the cloud.
  • CreateGroup creates a Microsoft 365 (unified) group unless groupTypes says otherwise; mailNickname defaults to the display name without spaces.
  • IsMemberOfGroup checks the signed-in user's membership.
  • ListGroupEvents with startDateTime and endDateTime reads the calendar view (recurring events expanded).
  • HttpRequest takes Uri (a full Graph URL or a path), Method, Body, ContentType and CustomHeader1 to CustomHeader5.

Not supported locally: HttpRequestV2.

Microsoft Teams​

Namespace: ctx.connectors.teams. Connection reference: shared_teams.

AreaOperationsPermission
TeamsGetAllTeams, GetAllAssociatedTeams, GetTeamTeam.ReadBasic.All
CreateATeamTeam.Create
AddMemberToTeamTeamMember.ReadWrite.All
ChannelsGetChannelsForGroup, GetAllChannelsForTeam, GetChannelChannel.ReadBasic.All
CreateChannelChannel.Create
AddMemberToChannel, RemoveMemberFromChannelTeamMember.ReadWrite.All
ChatsCreateChatChat.Create
GetChats, GetMessagesFromChatChat.Read
ListMembersChatMember.Read
MessagesPostMessageToConversation, PostCardToConversation, UpdateCardInConversationChannelMessage.Send, Chat.Create, Chat.ReadWrite, User.Read
ReplyWithMessageToConversation, ReplyWithCardToConversationChannelMessage.Send
GetMessagesFromChannel, ListRepliesToMessageChannelMessage.Read.All
GetMessageDetailsChannelMessage.Read.All, Chat.Read
PostFeedNotificationTeamsActivity.Send
TagsCreateTag, GetTags, DeleteTag, AddMemberToTag, DeleteTagMember, GetTagMembersTeamworkTag.ReadWrite
MentionsAtMentionUserUser.Read.All
AtMentionTagTeamworkTag.ReadWrite, User.Read.All
MeetingsCreateTeamsMeetingCalendars.ReadWrite, OnlineMeetings.ReadWrite
GraphHttpRequestUser.Read
await ctx.connectors.teams.PostMessageToConversation('PostToChannel', {
poster: 'User',
location: 'Channel',
body: {
recipient: { groupId: '0b6f2a3c-1111-4222-8333-944455556666', channelId: '19:abc123@thread.tacv2' },
messageBody: '<p>The weekly report is ready.</p>',
},
});

Local behaviour:

  • The post operations take the designer's parameters: location (Channel, Group chat or Chat with Flow bot), body/recipient/groupId + body/recipient/channelId for a channel, body/recipient (a chat id) for a group chat, body/recipient (an email, UPN or object id; several separated by ;) for the Flow bot, and body/messageBody. A nested body: { ... } object is flattened to these keys.
  • Messages are posted as the signed-in user, whatever poster says: a delegated Graph token cannot post as the Flow bot.
  • Chat with Flow bot is emulated: locally the message goes to the one-on-one chat between you and the recipient, created if needed. Deployed, it goes to the recipient's Workflows (Flow bot) chat. A recipient who is you fails locally (Graph cannot create a chat with yourself); use another recipient or a channel while testing.
  • Cards are posted as an Adaptive Card attachment.

Not supported locally: PostCardAndWaitForResponse ("Post adaptive card and wait for a response") and SubscribeUserMessageWithOptions. These wait for a person to answer, so they only work deployed. Call them with ctx.connectorWebhook and mock them locally; with a Graph token loaded they fail locally.

Word Online (Business)​

Namespace: ctx.connectors.wordonlinebusiness (or its alias ctx.connectors.wordonline; see the note below). Connection reference: shared_wordonlinebusiness. Permission: Files.ReadWrite.

OperationDesigner nameLocal aliases
CreateFileItemPopulate a Microsoft Word templatePopulateWordTemplate
GetFilePDFConvert Word Document to PDFConvertToPdf, ConvertWordDocumentToPdf
await ctx.connectors.wordonlinebusiness.CreateFileItem('FillContract', {
source: 'me',
drive: 'b!AbCdEf',
file: '/Templates/Contract.docx',
dynamicFileSchema: { '1325480521': 'Fabrikam', '1873251098': '2026-11-07' },
});

Local behaviour:

  • source is me (your OneDrive), users/<upn>, groups/<id>, sites/<id>, or a SharePoint site URL (resolved to the site). drive is the document library's drive id, file an item id or a path. A path that starts with the library name (/Shared Documents/...) is made library-relative.
  • Populate a template downloads the template and fills its content controls locally: each dynamicFileSchema/<id> value replaces the text of the content control with that numeric id, keeping the first run's formatting. Values are written as plain text: picture, repeating-section and other non-text controls are not emulated. The result is binary content (.docx), ready for a create-file action.
  • Convert to PDF uses Graph's PDF conversion and returns binary content (application/pdf).
  • PopulateWordTemplate and PopulateAWordTemplate are local aliases of CreateFileItem, and ConvertToPdf/ConvertWordDocumentToPdf of GetFilePDF; all of them run locally and are deployed under the cloud id.

Excel Online (Business)​

Namespace: ctx.connectors.excelonlinebusiness (or its alias ctx.connectors.excelonline; see the note below). Connection reference: shared_excelonlinebusiness. Permission: Files.ReadWrite.

OperationDesigner nameLocal aliases
GetItemsList rows present in a tableListRows
GetItemGet a rowGetRow
AddRowV2Add a row into a tableAddRow
PatchItemUpdate a rowUpdateRow
DeleteItemDelete a rowDeleteRow
GetTablesGet tables
GetAllWorksheetsGet worksheetsGetWorksheets
CreateTableCreate table
CreateWorksheetCreate worksheet
CreateIdColumnAdd a key column to a tableAddKeyColumn

FlowForger also accepts GetRange, UpdateRange, GetColumn, AddColumn, DeleteColumn, DeleteTable and DeleteWorksheet locally; they are Graph workbook calls without a designer counterpart.

await ctx.connectors.excelonlinebusiness.AddRowV2('AddOrder', {
source: 'me',
drive: 'b!AbCdEf',
file: '01ABCDEF2GHIJKLMNOPQRSTUVWXYZ',
table: 'Orders',
item: { OrderId: 'SO-1001', Status: 'Open' },
});

Local behaviour:

  • source, drive and file work as for Word. table is the table name; idColumn and id select the row for get, update and delete; item holds the row's values by column name.
  • Rows differ from the cloud's. Locally a row is { _rowIndex, <column>: <value>, ... } with the values as Graph returns them (numbers stay numbers). The cloud connector's rows carry @odata.etag and ItemInternalId and format their values differently. Mock GetItems with a real cloud output when later steps depend on the exact shape.
  • $filter and $orderby run on your machine, after the rows are read: $filter understands one condition (Column eq 'x', ne, contains(...), startswith(...), endswith(...)); an expression it does not recognise returns all rows. $top and $skip are applied before filtering.
  • Get, update and delete find the row by reading the whole table and comparing the key column as text.
  • AddRowV2 and PatchItem answer with the row as written; delete answers { ok: true, status: 204 }.
  • CreateIdColumn adds the column but does not fill it with key values.
  • RunScriptProd and RunScriptProdV2 (Run script) are accepted but are not expected to work locally: Office Scripts cannot be run through Microsoft Graph. Mock them.

OneDrive for Business​

Namespace: ctx.connectors.onedriveforbusiness. Connection reference: shared_onedriveforbusiness. Permission: Files.ReadWrite.

AreaOperations
FilesCreateFile, UpdateFile, DeleteFile, GetFileContent, GetFileContentByPath, GetFileMetadata, GetFileMetadataByPath
Copy and moveCopyDriveFile, CopyDriveFileByPath, MoveFile, MoveFileByPath, CopyFile (upload from URL)
ConvertConvertFile, ConvertFileByPath
Folders and searchListFolderV2 (ListFolder), ListRootFolder, FindFiles, FindFilesByPath
SharingCreateShareLinkV2 (CreateShareLink), CreateShareLinkByPathV2 (CreateShareLinkByPath)
OtherGetFileThumbnail

Local behaviour:

  • Everything runs against the signed-in user's own drive (/me/drive), whichever connection the deployed flow uses.
  • Metadata answers use the connector's { Id, Name, DisplayName, Path, LastModified, Size, MediaType, IsFolder, ETag, FileLocator, ... } fields with the original Graph properties kept alongside. Folder listings return a plain array.
  • GetFileContent, GetFileContentByPath, ConvertFile and ConvertFileByPath return binary content { "$content-type", "$content" } for anything but text/* (which is returned as text) and JSON (parsed), as in the cloud.
  • CreateFile and UpdateFile accept text, a base64 string, or binary content from another action (for example a populated Word template).
  • CopyFile downloads the source URL without authentication and uploads it.
  • CreateShareLinkV2 defaults to a view link with anonymous scope.

Not supported locally: ExtractFolderV2 (extract an archive). Mock it.

Namespace names and connection references​

The typed namespaces ctx.connectors.wordonline, ctx.connectors.excelonline and ctx.connectors.onedrive are aliases of ctx.connectors.wordonlinebusiness, ctx.connectors.excelonlinebusiness and ctx.connectors.onedriveforbusiness (the names flowforger pull generates): both spellings run locally and both are deployed as shared_wordonlinebusiness, shared_excelonlinebusiness and shared_onedriveforbusiness. A connections entry in flowforger.config.json may be keyed by either name. Declare the connection references in the constructor:

constructor(ctx: FlowContext) {
ctx.flow.connectionReferences = {
shared_wordonlinebusiness: {
apiId: '/providers/Microsoft.PowerApps/apis/shared_wordonlinebusiness',
connectionReferenceLogicalName: 'contoso_wordonline',
},
};
}

Failures​

A Graph error fails the action with outputs { statusCode, body }, where the body is Graph's own error object ({ error: { code, message } }), so a catch scope can read ctx.outputs('X')?.['statusCode']. A missing token fails the action with "Connector '...' not provided" and no outputs. See Outputs and failures.

These connectors do not follow @odata.nextLink for a pagination policy: locally a list operation returns its first page.

Packages​

@flowforger/connectors-office365, @flowforger/connectors-office365users, @flowforger/connectors-office365groups, @flowforger/connectors-teams, @flowforger/connectors-wordonline, @flowforger/connectors-excelonline, @flowforger/connectors-onedrive, sharing @flowforger/connectors-shared.