This is an MCP server that sends an email through Outlook. It also covers authentication scenarios.
- .NET 10 SDK
- Visual Studio Code with
- C# Dev Kit extension
- Azure CLI
- Azure Developer CLI
- Docker Desktop
-
Outlook Email MCP server runs in the following scenarios:
- OAuth authentication with Azure API Management as a remote MCP server
- API key authentication with Azure Functions as a remote MCP server
- No authentication as a locally running MCP server
-
Outlook Email MCP server includes:
Building Block Name Description Usage Tools send_emailSend an Email to recipients. #send_email
- Getting repository root
- Registering an app on Entra ID
- Running MCP server
- Connect MCP server to an MCP host/client
-
Get the repository root.
# bash/zsh REPOSITORY_ROOT=$(git rev-parse --show-toplevel)
# PowerShell $REPOSITORY_ROOT = git rev-parse --show-toplevel
This section is for running the MCP server on your local machine or in a local container. If you deploy this MCP server to Azure, you can skip this section.
-
Run the following script.
# bash/zsh cd $REPOSITORY_ROOT/outlook-email ./register-app.sh
# PowerShell cd $REPOSITORY_ROOT/outlook-email ./Register-App.ps1
-
Take notes for tenant ID, client ID and client secret values.
-
Run the MCP server app.
cd $REPOSITORY_ROOT/outlook-email dotnet run --project ./src/McpSamples.OutlookEmail.HybridApp
Make sure take note the absolute directory path of the
McpSamples.OutlookEmail.HybridAppproject.Parameters:
--http: The switch that indicates to run this MCP server as a streamable HTTP type. When this switch is added, the MCP server URL ishttp://localhost:5260.--tenant-id/-t: The tenant ID for sign-in.--client-id/-c: The client ID for sign-in.--client-secret/-s: The client secret for sign-in.
With these parameters, you can run the MCP server like:
dotnet run --project ./src/McpSamples.OutlookEmail.HybridApp -- --http -t "{{TENANT_ID}}" -c "{{CLIENT_ID}}" -s "{{CLIENT_SECRET}}"
Instead of providing those tenant ID, client ID and client secret values through the command-line, they can be stored as the user secrets.
dotnet user-secrets --project ./src/McpSamples.OutlookEmail.HybridApp set EntraId:TenantId "{{TENANT_ID}}" dotnet user-secrets --project ./src/McpSamples.OutlookEmail.HybridApp set EntraId:ClientId "{{CLIENT_ID}}" dotnet user-secrets --project ./src/McpSamples.OutlookEmail.HybridApp set EntraId:ClientSecret "{{CLIENT_SECRET}}"
-
Rename
local.settings.sample.jsontolocal.settings.json.# bash/zsh cp $REPOSITORY_ROOT/outlook-email/src/McpSamples.OutlookEmail.HybridApp/local.settings.sample.json \ $REPOSITORY_ROOT/outlook-email/src/McpSamples.OutlookEmail.HybridApp/local.settings.json
# PowerShell Copy-Item -Path $REPOSITORY_ROOT/outlook-email/src/McpSamples.OutlookEmail.HybridApp/local.settings.sample.json ` -Destination $REPOSITORY_ROOT/outlook-email/src/McpSamples.OutlookEmail.HybridApp/local.settings.json -Force
-
Open
local.settings.jsonand replace{{TENANT_ID}},{{CLIENT_ID}}and{{CLIENT_SECRET}}with the tenant ID, client ID and client secret values respectively. -
Run the MCP server app.
cd $REPOSITORY_ROOT/outlook-email/src/McpSamples.OutlookEmail.HybridApp func start
-
Build the MCP server app as a container image.
cd $REPOSITORY_ROOT docker build -f Dockerfile.outlook-email -t outlook-email:latest .
-
Run the MCP server app in a container.
docker run -i --rm -p 8080:8080 outlook-email:latest
Alternatively, use the container image from the container registry.
docker run -i --rm -p 8080:8080 ghcr.io/microsoft/mcp-dotnet-samples/outlook-email:latest
Parameters:
--http: The switch that indicates to run this MCP server as a streamable HTTP type. When this switch is added, the MCP server URL ishttp://localhost:8080.--tenant-id/-t: The tenant ID for sign-in.--client-id/-c: The client ID for sign-in.--client-secret/-s: The client secret for sign-in.
With these parameters, you can run the MCP server like:
# use local container image docker run -i --rm -p 8080:8080 outlook-email:latest --http -t "{{TENANT_ID}}" -c "{{CLIENT_ID}}" -s "{{CLIENT_SECRET}}"
# use container image from the container registry docker run -i --rm -p 8080:8080 ghcr.io/microsoft/mcp-dotnet-samples/outlook-email:latest --http -t "{{TENANT_ID}}" -c "{{CLIENT_ID}}" -s "{{CLIENT_SECRET}}"
-
IMPORTANT Check whether you have the necessary permissions:
- Your Azure account must have the
Microsoft.Authorization/roleAssignments/writepermission, such as Role Based Access Control Administrator, User Access Administrator, or Owner at the subscription level. - Your Azure account must also have the
Microsoft.Resources/deployments/writepermission at the subscription level.
- Your Azure account must have the
-
Navigate to the directory.
cd $REPOSITORY_ROOT/outlook-email
-
Login to Azure.
# Login with Azure Developer CLI azd auth login
-
Deploy the MCP server app to Azure.
azd up
While provisioning and deploying, you'll be asked to provide subscription ID, location, environment name.
-
After the deployment is complete, get the information by running the following commands:
-
Azure Functions Apps FQDN:
azd env get-value AZURE_RESOURCE_MCP_OUTLOOK_EMAIL_FQDN
-
Azure API Management FQDN:
azd env get-value AZURE_RESOURCE_MCP_OUTLOOK_EMAIL_GATEWAY_FQDN
-
-
Copy
mcp.jsonto the repository root.For locally running MCP server (STDIO):
mkdir -p $REPOSITORY_ROOT/.vscode cp $REPOSITORY_ROOT/outlook-email/.vscode/mcp.stdio.local.json \ $REPOSITORY_ROOT/.vscode/mcp.json
New-Item -Type Directory -Path $REPOSITORY_ROOT/.vscode -Force Copy-Item -Path $REPOSITORY_ROOT/outlook-email/.vscode/mcp.stdio.local.json ` -Destination $REPOSITORY_ROOT/.vscode/mcp.json -Force
For locally running MCP server (HTTP):
mkdir -p $REPOSITORY_ROOT/.vscode cp $REPOSITORY_ROOT/outlook-email/.vscode/mcp.http.local.json \ $REPOSITORY_ROOT/.vscode/mcp.json
New-Item -Type Directory -Path $REPOSITORY_ROOT/.vscode -Force Copy-Item -Path $REPOSITORY_ROOT/outlook-email/.vscode/mcp.http.local.json ` -Destination $REPOSITORY_ROOT/.vscode/mcp.json -Force
For locally running MCP server as Function app (HTTP):
mkdir -p $REPOSITORY_ROOT/.vscode cp $REPOSITORY_ROOT/outlook-email/.vscode/mcp.http.local-func.json \ $REPOSITORY_ROOT/.vscode/mcp.json
New-Item -Type Directory -Path $REPOSITORY_ROOT/.vscode -Force Copy-Item -Path $REPOSITORY_ROOT/outlook-email/.vscode/mcp.http.local-func.json ` -Destination $REPOSITORY_ROOT/.vscode/mcp.json -Force
For locally running MCP server in a container (STDIO):
mkdir -p $REPOSITORY_ROOT/.vscode cp $REPOSITORY_ROOT/outlook-email/.vscode/mcp.stdio.container.json \ $REPOSITORY_ROOT/.vscode/mcp.json
New-Item -Type Directory -Path $REPOSITORY_ROOT/.vscode -Force Copy-Item -Path $REPOSITORY_ROOT/outlook-email/.vscode/mcp.stdio.container.json ` -Destination $REPOSITORY_ROOT/.vscode/mcp.json -Force
For locally running MCP server in a container (HTTP):
mkdir -p $REPOSITORY_ROOT/.vscode cp $REPOSITORY_ROOT/outlook-email/.vscode/mcp.http.container.json \ $REPOSITORY_ROOT/.vscode/mcp.json
New-Item -Type Directory -Path $REPOSITORY_ROOT/.vscode -Force Copy-Item -Path $REPOSITORY_ROOT/outlook-email/.vscode/mcp.http.container.json ` -Destination $REPOSITORY_ROOT/.vscode/mcp.json -Force
For remotely running MCP server as Function app (HTTP):
mkdir -p $REPOSITORY_ROOT/.vscode cp $REPOSITORY_ROOT/outlook-email/.vscode/mcp.http.remote-func.json \ $REPOSITORY_ROOT/.vscode/mcp.json
New-Item -Type Directory -Path $REPOSITORY_ROOT/.vscode -Force Copy-Item -Path $REPOSITORY_ROOT/outlook-email/.vscode/mcp.http.remote-func.json ` -Destination $REPOSITORY_ROOT/.vscode/mcp.json -Force
For remotely running MCP server via API Management (HTTP):
mkdir -p $REPOSITORY_ROOT/.vscode cp $REPOSITORY_ROOT/outlook-email/.vscode/mcp.http.remote-apim.json \ $REPOSITORY_ROOT/.vscode/mcp.json
New-Item -Type Directory -Path $REPOSITORY_ROOT/.vscode -Force Copy-Item -Path $REPOSITORY_ROOT/outlook-email/.vscode/mcp.http.remote-apim.json ` -Destination $REPOSITORY_ROOT/.vscode/mcp.json -Force
-
Open Command Palette by typing
F1orCtrl+Shift+Pon Windows orCmd+Shift+Pon Mac OS, and searchMCP: List Servers. -
Choose
outlook-emailthen clickStart Server. -
When prompted, enter the following values:
- The absolute directory path of the
McpSamples.OutlookEmail.HybridAppproject. - The FQDN of Azure Container Apps.
- The FQDN of Azure Functions Apps.
- Tenant ID.
- Client ID.
- Client secret.
- The absolute directory path of the
-
Enter prompt like:
Send an email to abc@contoso.com from xyz@contoso.com with the subject of "lorem ipsum" and body of "hello world". -
Confirm the result.
{ "IsEncrypted": false, "Values": { "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated", "AzureWebJobsFeatureFlags": "DisableDiagnosticEventLogging", "UseHttp": "true", "EntraId__TenantId": "{{TENANT_ID}}", "EntraId__ClientId": "{{CLIENT_ID}}", "EntraId__ClientSecret": "{{CLIENT_SECRET}}", "EntraId__UseManagedIdentity": false } }