使用 Microsoft Graph API 和 PowerShell 发送电子邮件
要从 PowerShell 脚本通过 SMTP 服务器发送电子邮件,您可以使用内置的 Send-MailMessage cmdlet。它的主要缺点是它只能使用基本 SMTP 身份验证,不支持现代身份验证方法,包括 OAuth 和 Microsoft 现代身份验证。当你运行Send-MailMessage在新版本的 PowerShell Core 7.x 中运行命令时,您会收到以下警告:
WARNING: The command 'Send-MailMessage' is obsolete. This cmdlet does not guarantee secure connections to SMTP servers. While there is no immediate replacement available in PowerShell, we recommend you do not use Send-MailMessage at this time. See https://aka.ms/SendMailMessage for more information.

默认情况下,Microsoft 为所有新的 Azure 租户禁用基本身份验证。在本文中,我们将了解如何使用 Microsoft Graph API 和 PowerShell 从 Exchange Online/Microsoft 365 租户发送电子邮件。
内容:
- 配置使用 Microsoft Graph API 发送电子邮件的权限
- 使用 Invoke-RestMethod 通过 Exchange Online 发送电子邮件
- 使用 Microsoft.Graph 模块中的 Send-MgUserMail Cmdlet
在获取 Azure 令牌并通过 PowerShell 脚本进行身份验证之前,您需要在 Entra ID 租户中创建一个新应用程序 (Azure 活动目录->应用程序注册->新注册)。然后授予Mail.Send应用程序的权限(API 权限 -> 添加权限 -> Microsoft Graph -> 应用程序权限 -> Mail.Send)。


在“使用 PowerShell 连接到 Microsoft Graph API”一文中了解如何为 Microsoft Graph 注册 Azure 应用程序。
默认情况下,您的应用程序可以代表 Exchange Online 租户中的任何邮箱发送电子邮件。您可以使用应用程序访问策略来限制您的应用程序可以代表其发送电子邮件的电子邮件地址列表。
使用 PowerShell 连接到 Exchange Online (Connect-ExchangeOnline),创建一个 Exchange 通讯组,并添加您希望能够从中发送电子邮件的帐户:
New-DistributionGroup -Name "azappSendasAllowed" -Type "Security" -Members @("[email protected]")
如果您愿意,还可以从 Exchange 全局地址列表 (GAL) 中隐藏该组:
Set-DistributionGroup -Identity azappSendasAllowed -HiddenFromAddressListsEnabled $true
现在创建一个策略并将其绑定到您的 Azure AppID:
New-ApplicationAccessPolicy -AppId "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -PolicyScopeGroupId azappSendasAllowed -AccessRight RestrictAccess -Description "Resrtict SendAs Policy"


您现在可以检查您的应用程序可以代表哪些地址发送电子邮件:
Test-ApplicationAccessPolicy -Identity [email protected] -AppId "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Test-ApplicationAccessPolicy -Identity [email protected] -AppId "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
根据访问状态,上述命令将返回 Denied 或 Granted。


使用 Invoke-RestMethod 通过 Exchange Online 发送电子邮件
您可以使用 sendMail REST API 方法通过 Exchange Online/Microsoft 365 发送电子邮件。若要调用该方法,请使用内置调用RestMethodPowerShell cmdlet。
要使用 Microsoft Graph API 发送电子邮件,您必须使用 Entra ID (Azure) 进行身份验证并获取令牌。
$AccessSecret= "3333333333333333333333333333333333333333333"
$AzureAppID = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$tenantID="1234567-1234-1234-1234-123456789012"
现在连接到 Graph API 并执行身份验证:
$tokenBody = @{
Grant_Type = "client_credentials"
Scope = "https://graph.microsoft.com/.default"
Client_Id = $AzureAppID
Client_Secret = $AccessSecret
}
$tokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenantID/oauth2/v2.0/token" -Method POST -Body $tokenBody
$headers = @{
"Authorization" = "Bearer $($tokenResponse.access_token)"
"Content-type" = "application/json"
}
您现在可以发送电子邮件了:
$MailFrom = "[email protected]"
$MailTo = "[email protected]"
$URLsend = "https://graph.microsoft.com/v1.0/users/$MailFrom/sendMail"
$BodyJsonsend = @"
{
"message": {
"subject": "Test email from Microsoft Graph API",
"body": {
"contentType": "HTML",
"content": "This email is sent via <br>
Microsoft GRAPH API<br>"
},
"toRecipients": [
{
"emailAddress": {
"address": "$mailto"
}
}
]
},
"saveToSentItems": "true"
}
"@
Invoke-RestMethod -Method POST -Uri $URLsend -Headers $headers -Body $BodyJsonsend
检查电子邮件是否已成功传送到用户的 Exchange 邮箱。


使用 Microsoft.Graph 模块中的 Send-MgUserMail Cmdlet
使用 Invoke-RestMethod cmdlet 发送电子邮件意味着您必须生成 JSON 格式的整个电子邮件对象。为了使该过程更容易,您可以尝试使用发送-MgUserMail而是来自 Microsoft.Graph 模块的 cmdlet。
安装微软Graph模块并将其导入到您的 PowerShell 会话中:
Install-Module Microsoft.Graph
Import-Module Microsoft.Graph
我们将使用证书在 Microsoft 365 (Exchange Online) 租户中进行身份验证:
$certThumbprint = "9CF05589A4B29BECEE6456F08A76EBC3DC2BC581" $AzureAppID = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" $tenant="woshub.onmicrosoft.com" Connect-MgGraph -TenantId $Tenant -ClientId $AzureAppID -CertificateThumbprint $certThumbprint
接下来,我们创建一封带有 HTML 正文和附件的简单电子邮件:
$MailFrom = "[email protected]"
$MailTo = "[email protected]"
$msgBody = “This is <br> test <br> Graph API mailer <br>”
$Attachment = "C:logsmytestapp.log"
$AttachmentContentBytes = [System.IO.File]::ReadAllBytes($Attachment)
$AttachmentBase64 = [System.Convert]::ToBase64String($AttachmentContentBytes)
$Message = @{
Subject = "Hello World from GraphAPI"
Body = @{
ContentType = "HTML"
Content = $msgBody
}
ToRecipients = @(
@{
EmailAddress = @{
Address = $MailTo
}
}
)
Attachments = @(
@{
"@odata.type" = "#microsoft.graph.fileAttachment"
Name = (Split-Path $Attachment -Leaf)
ContentType = "application/octet-stream"
ContentBytes = $AttachmentBase64
}
)
}


您可以使用此命令发送电子邮件:
Send-MgUserMail -UserId $MailFrom -Message $Message
Send-MgUserMail cmdlet 只能用于通过 Exchange Online 发送电子邮件。这意味着它无法与本地 Exchange Server 或其他电子邮件/SMTP 提供商一起使用。
