PowerShellによるOutlookメール作成

## ◦ 目的・動機
一般的な企業で勤務されている方であれば、ある程度定型化・定期化されたメール送信作業があると思います。
例えば、リモートワークの連絡や残業・休暇申請。テンプレのテキストをコピペして、件名や送信先、日時を入力をしたりと。難しくはないけれどちょっとしたミスで上司や人事の人に迷惑をかけたりとそれなりに面倒な作業ですよね。
そんなメールの作成を少しでも楽にすることが目的・動機です。
### ▶ ※注意書き※
自分が見直す用の仕様メモとしての意味合いが強い記事なので、懇切丁寧なプログラムの解説記事ではありません。悪しからず。

## ◦ 環境
```powershell
$PSVersionTable.PSVersion

Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      18362  1171
```
## ◦ プログラム
powershellのプログラムは以下になります。
プログラムが読込むテンプレは別に用意します。

```powershell:MakeDraft.ps1
$tmppath = "hoge" #テンプレが保存されてるフォルダ

# 入力によってテンプレートを指名
# stringの1文字に制限
[validateLength(1,1)]$in = [string](Read-Host "テンプレートを選択して下さい。`r`n
    template1:`r`n
    template2:`r`n
    template3:`r`n"
    )

# プログラム実行時の日付取得
$today = Get-Date
# 来週の月・金曜の日付取得
$nextweek = @{mon = ""; fri = ""}
$nextweek["fri"] = $today.AddDays([int][dayofweek]::Friday - $today.DayOfWeek)    
if ($today -ge $nextweek["fri"]) {
    $nextweek["fri"] = $nextweek["fri"].AddDays(7)
}
$nextweek["mon"] = $nextweek["fri"].AddDays(-4)

switch($in)
{
    "1" {
        $file_name = "01.txt";
        $mailbody = "01_body.txt"
        # 件名にメール送信日を含めるための準備
        $subject_dates = $today.ToString("MM/dd")
        }
    "2" {
        $file_name = "02.txt";
        $mailbody = "02_body.txt"
        # 件名に来週の月・金曜の日付を含めるための準備
        $subject_dates = $nextweek["mon"].ToString("MM/dd")+ " - " + $nextweek["fri"].ToString("MM/dd")
        }
    "3" {
        $file_name = "03.txt";
        $mailbody = "03_body.txt"
        }
    # 入力が不適切だった場合の処理
    default {Write-Host "input error"; exit}
}

# file読込
cd $tmppath
if(Test-Path $file_name){
    $file = $(Get-Content $file_name)
}else{
    Write-Host "file_name error"
    exit
}

# 下書き作成
$outlook = New-Object -ComObject Outlook.Application
$mail = $outlook.createItem(0)
# body(本文)以外の読込
foreach($line in $file){
    if($line -match "(?<mail_key>^\w*):(?<mail_value>.*$)"){
        # 件名の取得
        if($Matches.ContainsValue("subject")){
            $Matches["mail_value"] += $subject_dates
            $mail.Subject = $Matches["mail_value"]
        }
        # 宛先(to)の取得
        elseif($Matches.ContainsValue("recipients_to")){
            $mail.Recipients.Add($Matches["mail_value"]).type = 1
        }
        # 宛先(cc)の取得
        elseif($Matches.ContainsValue("recipients_cc")){
            $mail.Recipients.Add($Matches["mail_value"]).type = 2
        }else{
            # Write-Host "match error"
            # $Matches
        }
    }
}
# body(本文)の読込
if(Test-Path $mailbody){
    $i = 0
    $mailbody_f = @()
    foreach($l in Get-Content $mailbody){
        if($l -match "[A-Z]+"){
            $l = $l -replace "[A-Z]+DAY", $nextweek["mon"].AddDays($i).ToString("MM/dd")
            $i++
        }
        $mailbody_f += $l
    }
     $mail.body = $mailbody_f -join "`r`n"
}else{
    Write-Host "mailbody error"
    exit
}

$mail.save()
$inspector = $mail.GetInspector
$inspector.Display()
```

## ◦ テンプレ
### ▶ メール本文以外の情報(例:01.txt)
```
■送付宛先
recipients_to:to_hoeg@mail.com
recipients_cc:cc_fuga@mail.com

■件名
subject:勤務開始連絡
```

### ▶ メール本文の情報(例:01_body.txt)
```
各位

お疲れ様です。
XXです。

これより、勤務開始します。

以上、宜しくお願いします。
```

### ▶ メール本文以外の情報(例:02.txt)
```
■送付宛先
recipients_to:to_hoeg@mail.com
recipients_cc:cc_fuga@mail.com

■件名
subject:テレワーク申請
```

### ▶ メール本文の情報(例:02_body.txt)
```
各位

お疲れ様です。
XXです。

下記の日程で、テレワークを申請いたします。

＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
MONDAY（月）テレワーク
TUESDAY（火）テレワーク
WEDNESDAY（水）テレワーク
THURSDAY（木）テレワーク
FRIDAY（金）テレワーク
＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝

以上、よろしくお願いします。
```

## ◦ プログラム詳細
### ▶ テンプレの指定
ValidateLength(1,1)を利用することで標準入力を1文字に制限しています。

```powershell
# 入力によってテンプレートを指名
# stringの1文字に制限
[validateLength(1,1)]$in = [string](Read-Host "テンプレートを選択して下さい。`r`n
    1(template1):`r`n
    2(template2):`r`n
    3(template3):`r`n"
    )
```

### ▶ 日時情報の取得
メール送信時の日付と来週の月・金曜の日付を取得しています。
日付情報は件名や本文に含めることを想定しています。

```powershell
# プログラム実行時の日付取得
$today = Get-Date
# 来週の月・金曜の日付取得
$nextweek = @{mon = ""; fri = ""}
$nextweek["fri"] = $today.AddDays([int][dayofweek]::Friday - $today.DayOfWeek)    
if ($today -ge $nextweek["fri"]) {
    $nextweek["fri"] = $nextweek["fri"].AddDays(7)
}
$nextweek["mon"] = $nextweek["fri"].AddDays(-4)
```

### ▶ テンプレから件名・宛先情報を取得
テンプレを読込んで各行を正規表現でチェックしています。
正規表現 ***^\w\**** で行頭の英数字をチェックし"mail_key"に格納、
そのあとの ***:*** を区切りにして、
正規表現 ***.\*$*** で行末までの情報を"mail_value"に格納しています。

例の01.txtを参考にすると
***subject:勤務開始連絡*** の行は以下のように情報を格納します。
mail_key:subject
mail_value:勤務開始連絡

```powershell
# body以外の読込
foreach($line in $file){
    if($line -match "(?<mail_key>^\w*):(?<mail_value>.*$)"){
        # 件名の取得
        if($Matches.ContainsValue("subject")){
            $Matches["mail_value"] += $subject_dates
            $mail.Subject = $Matches["mail_value"]
        }
        # 宛先(to)の取得
        elseif($Matches.ContainsValue("recipients_to")){
            $mail.Recipients.Add($Matches["mail_value"]).type = 1
        }
        # 宛先(cc)の取得
        elseif($Matches.ContainsValue("recipients_cc")){
            $mail.Recipients.Add($Matches["mail_value"]).type = 2
        }else{
            # Write-Host "match error"
            # $Matches
        }
    }
}
```

### ▶ テンプレからメール本文を取得
テンプレ内の曜日を正規表現 ***[A-Z]+DAY*** でチェックします。
曜日部分を事前に取得した日付情報で置き換えます。
読込んだテンプレの各行を配列に格納し、改行を区切り文字としてメール本文の変数に格納します。

```powershell
if(Test-Path $mailbody){
    $i = 0
    $mailbody_f = @()
    foreach($l in Get-Content $mailbody){
        if($l -match "[A-Z]+DAY"){
            $l = $l -replace "[A-Z]+DAY", $nextweek["mon"].AddDays($i).ToString("MM/dd")
            $i++
        }
        $mailbody_f += $l
    }
     $mail.body = $mailbody_f -join "`r`n"
}
```


## ◦ 蛇足
読込んだテンプレ本文を期待通りメール本文で改行させたり
日付情報を本文に入れ込むことが大変でした。
こんなメール作成したいのだけれど期待通り動作しませんなど意見あれば
コメントしてみてください。対応するかもしれません。