Qiitaの記事を参考にPowerShellでGmailを送信するスクリプトを書いてみたときのメモ

以下の記事を参考にしてPowerShellGmailを送信するスクリプトを書いてみた。
この記事のGoogleアカウントの設定に関する説明には、とても助けられた。
今まで「アプリパスワード」なるものが存在するとは知らず、自分のパスワードを使用して認証に失敗し諦めていたが、説明されている手順で設定をしたらメールを送信できるようになった。
ありがとうございます。

qiita.com


さて、アプリのパスワードは後で必要になるので忘れず記録しておこう。
とりあえずはユーザー環境変数app_passwordに設定し、
(get-childitem env:app_password).value
で取得するようにした。ユーザ名(メールアドレス,e.g "johndoe@gmail.com")も同様にユーザー環境変数から取得するようにした。

関数は[CmdletBinding()]属性でadvanced functionの形にしよう。
from, to, subject は必須にして、toはパイプラインから受け取れるようにした。

以下のパラメーター で添付ファイルを指定できる。

  • Attachments

Send-MailMessage

関数定義
function SendMail {
  [CmdletBinding()]
  param(
        [Parameter(Mandatory=$True)]
        [ValidateNotNullOrEmpty()]
        [string]$From,

        [Parameter(Mandatory=$True,
                   ValueFromPipeline=$True)]
        [ValidateNotNullOrEmpty()]
        [string[]]$To,

        [Parameter(Mandatory=$True)]
        [ValidateNotNullOrEmpty()]
        [string]$Subject,

        [string]$Body,
        [string[]]$Attach
  )

  begin {
  }
  process {
    $SMTPServer = "smtp.gmail.com" 
    $SMTPPort = 587
    $app = (get-childitem env:app_password).value
    $password = ConvertTo-SecureString $app -AsPlainText -Force
    $username = (get-childitem env:app_username).value
    $credential = New-Object System.Management.Automation.PSCredential($username, $password)

    $cmd = 'Send-MailMessage `
        -From $From `
        -to $To `
        -Subject $Subject `
        -Body $Body `
        -SmtpServer $SMTPServer `
        -port $SMTPPort `
        -UseSsl -Credential $credential `
        -DeliveryNotificationOption None `
        -Encoding UTF8 `
        -ErrorAction Stop'

    if( -not [string]::IsNullOrEmpty($attach) ){
        $cmd += ' -Attachments $attach'
    }

    invoke-expression $cmd

  }
  end {
  }
}
実行例
$f = "johndoe@gmail.com"
$t = @()
$t += "xxx@yahoo.co.jp"
$t += "yyy@yahoo.co.jp"
$a = "Test of Send-MailMessage"
$b = "Hello PowerShell World!"

# parameter
SendMail -from $f -to $t -subject $a -body $b

#pipeline
$t  |  SendMail -from $f -subject $a -body $b

パラメーター指定の場合は送信先が配列のまま渡されるので送信範囲が見えてしまう。
グループのメンバーに業務連絡するようなケースといえよう。
一方、パイプライン渡しの場合は配列の要素ごとに逐次処理されるので、送信範囲をみせないように個別にメールを送信したいケースといえよう。
パラメーター指定の場合とパイプライン渡しの場合の挙動の違いは以前、紹介した。
『PowerShell実践ガイドブック』吉崎生(Kindle版)をPC版Kindleで読む - willwealth’s diary

Microsoftからの警告

せっかく作った関数だがMicrosoftからはSend-MailMessageは使わないようにと警告が出ている。
しかし当面、代替手段がなければ状況によっては使わざるをえないこともあるかもしれない。
Send-MailMessage (Microsoft.PowerShell.Utility) - PowerShell | Microsoft Docs