agentleFS
Microsoft AzureKnown publisherAzure/connectors-python-sdk/.github/skills/trigger-registration/SKILL.md

trigger-registration

Skill0 starsChanged 18 days agoMITView on GitHub

Register Connector Namespace trigger configs for Azure connectors and scaffold Azure Functions to receive trigger callbacks. USE WHEN: setting up polling triggers (e.g., OnNewEmail, OnNewFile, OnUpdatedFile) that call back to an Azure Function, scaffolding a Function App project with ConnectorTrigger binding, wiring callback URLs, or troubleshooting trigger configs. Covers both typed SDK payloads and raw JSON generic triggers. NOT FOR: connection setup (use connection-setup skill).

2 other projects use a version of this, 2 of them edited.

Adopted by

Most recently taken up by

  • Other versions2 projects use a version of this.

    Word for word · 0

    None found.

    Wrote their own version · 0

    None found.

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repository3 other files it gives its agents.

The file

We split this skill into the rules it gives an agent

6 rules. About 0 are common, 2 are distinctive, and 4 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Use this decision logic when scaffolding a Python connector trigger function:

    line 32
  2. Very specific:

    No typed model available → use str as parameter type, no extra package needed beyond azure-functions

    line 40
  3. Very specific:

    Add to requirements.txt (include packages based on your approach):

    line 90
  4. Very specific:

    Start Azurite (required for AzureWebJobsStorage):

    line 157
  5. Distinctive:

    Start the Function App:

    line 188
  6. Very specific:

    Use credentials from azure.identity.aio.

    line 346

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Connector Namespace Trigger Registration

Registers polling trigger configs on a Connector Namespace so that connector events (new email, new file, etc.) call back to your application endpoint. Covers scaffolding a Python Function App with the ConnectorTrigger extension binding.

When to Use

  • Developer needs a connector trigger (e.g., "when a new email arrives in Office365")
  • Developer has an existing Connector Namespace connection (use the connection-setup skill first if not)
  • Developer needs to scaffold a Python Function App with ConnectorTrigger in Azure Functions
  • Developer needs to wire the callback URL from a deployed or local Function App
  • Developer needs to understand which typed payload to use for a given trigger operation

Prerequisites

  • Azure CLI installed and authenticated (az login)
  • Connector Namespace with a connected connector (see connection-setup skill)
  • The Connector Namespace must have a system-assigned managed identity enabled
  • Supported regions for Connector Namespace: westcentralus
  • A supported Python version for Azure Functions with the azure-connectors package installed

Key Concepts

ConnectorTrigger Extension Binding

Python Decorator and Package Rules

Use this decision logic when scaffolding a Python connector trigger function:

  1. Add connector_trigger decorator:
    • @app.connector_trigger
  2. Choose packages by trigger operation:
    • Office 365 OnNewEmail → add azurefunctions-extensions-connectors (imports azure-connectors automatically)
    • Any other connector with a typed SDK model → add azure-connectors, use typed class as parameter type
    • No typed model available → use str as parameter type, no extra package needed beyond azure-functions
  3. Base package: azure-functions
    • Python 3.13 → >=2.2.0b4
    • Python < 3.13 → >=1.26.0b3

Extension Webhook Endpoint

The ConnectorTrigger extension registers a webhook route on the Function App:

POST /runtime/webhooks/connector?functionName={FunctionName}&code={connector_extension_key}
  • functionName must exactly match the @app.function_name(name="...") value
  • connector_extension is a system key auto-generated when the extension loads
  • Locally (func start), the system key is not enforced

Trigger Config vs Connection

Connector Namespace
├── connections/
│   └── office365-conn         ← auth + runtime URL (connection-setup skill)
└── triggerConfigs/
    └── onnewemail-trigger     ← poll + callback config (THIS skill)

Scaffolding a Python Function App

1. Initialize with azd

azd init -t functions-quickstart-python-http-azd

2. Update host.json for preview extension bundle

{
    "version": "2.0",
    "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle.Preview",
        "version": "[4.*, 5.0.0)"
    }
}

3. Install packages

Add to requirements.txt (include packages based on your approach):

# >=2.2.0b4 required for Python 3.13+, >=1.26.0b3 for Python < 3.13
azure-functions>=2.2.0b4

# Currently only supports Office 365 OnNewEmail operation
azurefunctions-extensions-connectors

# Required for str payloads, don't include if using azurefunctions-extensions-connectors 
azure-connectors

4. Create a ConnectorTrigger function

With typed SDK payload (Office 365 email example)

import azure.functions as func
import azurefunctions.extensions.connectors.office365 as office365
import logging
from typing import List

app = func.FunctionApp()


@app.function_name(name="OnNewEmail")
@app.connector_trigger(arg_name="emails")
def on_new_email(emails: List[office365.ClientReceiveMessage]) -> None:
    logging.info("OnNewEmail trigger received")

    for email in emails:
        logging.info(f"Subject: {email.subject}")
        logging.info(f"From: {email.from_}")

With connector trigger and raw JSON (when no typed SDK model exists)

import azure.functions as func
import json
import logging

app = func.FunctionApp()


@app.function_name(name="OnNewFile")
@app.connector_trigger(arg_name="payload")
def on_new_file(payload: str) -> None:
    logging.info("OnNewFile trigger received")

    data = json.loads(payload)
    body = data.get("body", {})

    if isinstance(body, dict) and "value" in body:
        # Metadata trigger — batch of items
        for item in body["value"]:
            logging.info(f"File: {item.get('name')}")
    elif isinstance(body, str):
        # Binary trigger — base64-encoded file content
        import base64
        content = base64.b64decode(body)
        logging.info(f"Received file content: {len(content)} bytes")

5. Run locally

Start Azurite (required for AzureWebJobsStorage):

npx azurite

Verify local.settings.json:

  • Python 3.13+ example:
{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "python"
  }
}
  • Python < 3.13 example - PYTHON_ISOLATE_WORKER_DEPENDENCIES enabled:
{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "python",
    "PYTHON_ISOLATE_WORKER_DEPENDENCIES": "1"
  }
}

Start the Function App:

func start

The extension logs the webhook endpoint at startup:

Connector endpoint: http://localhost:7071/runtime/webhooks/connector

Registering a Trigger Config

Step 1: Get the Callback URL

Deployed Function App

$resourceGroup = "<resource-group>"
$functionAppName = "<function-app-name>"
$functionName = "<function-name>"  # must match @app.function_name(name="...")

$connectorExtensionKey = az functionapp keys list -g $resourceGroup -n $functionAppName --query "systemKeys.connector_extension" -o tsv
$callbackUrl = "https://$functionAppName.azurewebsites.net/runtime/webhooks/connector?functionName=$functionName&code=$connectorExtensionKey"

Local development (with dev tunnel)

$tunnelUrl = "<your-tunnel-url>"  # e.g., https://<id>-7071.uks1.devtunnels.ms
$functionName = "<function-name>"
$callbackUrl = "$tunnelUrl/runtime/webhooks/connector?functionName=$functionName"

Step 2: Create Trigger Config

$subscriptionId = "<subscription-id>"
$resourceGroup = "<resource-group>"
$namespaceName = "<namespace-name>"
$nsId = "/subscriptions/$subscriptionId/resourceGroups/$resourceGroup/providers/Microsoft.Web/connectorGateways/$namespaceName"

$triggerName = "<trigger-config-name>"   # e.g., "onnewemail-trigger"
$connectionName = "<connection-name>"    # e.g., "office365-conn"
$connectorName = "<connector-name>"      # e.g., "office365"
$operationName = "<operation-name>"      # e.g., "OnNewEmailV3"

$token = az account get-access-token `
    --resource "https://management.core.windows.net/" `
    --query "accessToken" -o tsv

$body = @{
    properties = @{
        operationName = $operationName
        connectionDetails = @{
            connectorName = $connectorName
            connectionName = $connectionName
        }
        notificationDetails = @{
            callbackUrl = $callbackUrl
            httpMethod = "Post"
        }
        parameters = @(
            # Office 365 OnNewEmailV3:
            # @{ name = "folderPath"; value = "Inbox" }

            # OneDrive for Business OnNewFile:
            # @{ name = "folderId"; value = "root" }
        )
    }
} | ConvertTo-Json -Depth 4

$uri = "https://management.azure.com${nsId}/triggerConfigs/${triggerName}?api-version=2026-05-01-preview"
try {
    $response = Invoke-WebRequest -Uri $uri -Method PUT -Body $body `
        -ContentType "application/json" `
        -Headers @{ Authorization = "Bearer $token" }
    Write-Output "Status: $($response.StatusCode)"
} catch {
    Write-Output "Error: $($_.Exception.Response.StatusCode)"
    $_.ErrorDetails.Message
}

Step 3: Verify Trigger Config

az rest --method GET `
    --uri "https://management.azure.com${nsId}/triggerConfigs/${triggerName}?api-version=2026-05-01-preview" `
    --query "properties.{operation:operationName, state:state, callback:notificationDetails.callbackUrl}" `
    -o table

Expected: state = Enabled.

Step 4: Test the Trigger

Trigger the connector event (e.g., send an email, upload a file). The Connector Namespace polls every 1-5 minutes.

Watch Function App logs:

func start  # local
# or for deployed:
az functionapp log tail -g $resourceGroup -n $functionAppName

Using the SDK for Actions (Beyond Triggers)

The azure-connectors package provides async-only root clients for calling connector actions directly from Python applications. Clients accept caller-owned AsyncTokenCredential or AzureKeyCredential credentials; no synchronous mirror is provided.

Example: Send an email

from azure.identity.aio import DefaultAzureCredential

from azure.connectors.office365 import Office365Client
from azure.connectors.office365 import SendEmailInput


async def main(connection_url: str):
    async with DefaultAzureCredential() as credential:
        async with Office365Client(connection_url, credential) as client:
            await client.send_email(
                input=SendEmailInput(
                    to="recipient@example.com",
                    subject="Hello from Python SDK",
                    body="<p>Sent from any Python app.</p>",
                )
            )

Example: List SharePoint items

from azure.identity.aio import DefaultAzureCredential

from azure.connectors.sharepointonline import SharepointonlineClient


async def list_items(connection_url: str):
    async with DefaultAzureCredential() as credential:
        async with SharepointonlineClient(connection_url, credential) as client:
            items = [
                item
                async for item in client.list_items(
                    dataset="https://contoso.sharepoint.com/sites/MySite",
                    table="MyList",
                )
            ]

    for item in items:
        print(f"Item: {item.get('Title')}")

Authentication Options

Use credentials from azure.identity.aio. Use AzureKeyCredential from azure.core.credentials when the connection runtime expects an API key. The caller owns async credentials and must close them with async with or await credential.close().

E2E Validated Connectors

ConnectorPackageStatus
Office 365 Outlookazure.connectors.office365✅ Complete
SharePoint Onlineazure.connectors.sharepointonline✅ Complete
Microsoft Teamsazure.connectors.teams✅ Complete
Azure Data Explorerazure.connectors.kusto✅ Complete
MS Graph Groups & Usersazure.connectors.msgraphgroupsanduser✅ Complete
Office 365 Usersazure.connectors.office365users✅ Complete
Azure Blob Storageazure.connectors.azureblob✅ Complete
IBM MQazure.connectors.mq✅ Complete

All SDKs support generating clients for any of the 1,000+ Azure managed connectors.

Trigger Payload Shapes

The Connector Namespace delivers callbacks in two shapes depending on the connector's splitOn setting:

ShapeJSON StructureWhen
Batch{"body": {"value": [...items...]}}splitOn disabled (default)
Single-item{"body": {...item properties...}}splitOn enabled

The SDK's TriggerCallbackPayload.from_json() and TriggerCallbackBody.from_dict() methods normalize both shapes into a list, so consumers always iterate:

from azure.connectors.sdk import TriggerCallbackPayload

payload = TriggerCallbackPayload.from_json(raw_json)
for item in payload.body.value:
    print(item)

Common Errors

ErrorCauseFix
Could not find member 'connectionName'Used connectionName at top levelWrap in connectionDetails object
Could not find member 'callbackUrl'Put callbackUrl at properties levelWrap in notificationDetails object
Could not find member 'parameterName'Used parameterName in params arrayUse name field instead
Trigger provisions but never firesMissing notificationDetails or empty callbackUrlEnsure notificationDetails.callbackUrl is set
az rest PUT returns no outputaz rest swallows non-2xx responsesUse Invoke-WebRequest for PUT operations

Reference

For a complete mapping of trigger operations to function signatures across .NET, Python, and TypeScript, see Operations to Functions Signature Match.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.