だるろぐ

明日できることは、今日しない。

PowerShell:メールが文字化けする

PowerShell で SmtpClient を使ってメールを送ったのだけど、件名が化けてしまった。

NET 4.5 では内部でエンコードされた件名をデコードして持つように実装が変わったので、2 回エンコードして元の文字列が保持されるようにしないといけないということでした。

.NET 4.5 で SmtpClient の挙動が変わっていたらしい - しばやん雑記

よくわかんないのだけど、"ISO-2022-JP と Base64 でエンコードするような処理"を件名に対して2回行えばいいらしい。リンク先のコード(C#)をそのまま PowerShell に書き換えてみた。

#「=?iso-2022-jp?B?<エンコード文字列>?=」形式に変換
function Encode-MailHeader($subject)
{
    $enc = [System.Text.Encoding]::GetEncoding("iso-2022-jp");
    $strBase64 = [Convert]::ToBase64String($enc.GetBytes($subject));

    "=?{0}?B?{1}?=" -f "iso-2022-jp", $strBase64
}

あとはこの関数を使って、

$subject = Encode-MailHeader(Encode-MailHeader($title))

とでもすればよい。とりあえず文字化けはなくなった気がする。

今日学んだこと

関数をパイプ対応にする

これで完成――でもいいのだけど、なんかダサいので、パイプで繋げるようにしてみた。

#「=?iso-2022-jp?B?<エンコード文字列>?=」形式に変換
function Encode-MailHeader([Parameter(ValueFromPipeline=$true)]$subject)
{
    process
    {
        $enc = [System.Text.Encoding]::GetEncoding("iso-2022-jp");
        $strBase64 = [Convert]::ToBase64String($enc.GetBytes($subject));

        "=?{0}?B?{1}?=" -f "iso-2022-jp", $strBase64
    }
}

パイプを処理できるように、さっきの関数を改良。

$subject = $title | Encode-MailHeader | Encode-MailHeader

ちょっとだけスマートになった気がする。