使用 Microsoft Graph API 和 PowerShell 發送電子郵件

Jacki

要從 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 租戶發送電子郵件。

內容:

在獲取 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 提供商一起使用。

了解更多:如何使用 PowerShell 閱讀 Outlook 電子郵件