新規メール作成スクリプト clip2mail.ps1

前回、Windowsのシステムクリップボードに保存されているテキストをスマホへ送信する方法として、保存テキストをベースに新規メールを自動生成する次のPowerShellスクリプト「clip2mail.ps1」を作成した。

#!/usr/bin/env pwsh

#========================================================================
# システムクリップボードのテキストでメールを作成
#========================================================================

#========================================================================
# Thunderbirdアプリケーションパス
#========================================================================
$mailer='C:\Program Files\Mozilla Thunderbird\thunderbird.exe'

#========================================================================
# 本文の上限文字数
#========================================================================
$bodycharlimit = 32000

#========================================================================
# 宛先とサブジェクト
#========================================================================
$to=$env:DEFAULT_TO_EMAIL
$title="Windowsシステムクリップボード"

#========================================================================
# システムクリップボードのテキストをThunderbirdのコンポーザに貼り付け
# できるフォーマットへ変換
#========================================================================
$body=$(Get-Clipboard | Out-String)

$body=$body -replace " "," "

#========================================================================
# 引数で指定できる文字列長には上限がある。上限を超えている場合には、条件
# 未満まで文字数を減らして使用する。
#========================================================================
if ($body.Length -gt $bodycharlimit) {
    $body = $body.Substring(0, $bodycharlimit)
}

#========================================================================
# メールを作成
#========================================================================
& $mailer                               `
    -compose                            `
    "to='$to',subject='$title',body='$body'"

新規メールの作成には、Thunderbirdのメールコンポーザを使っている。コマンドラインオプションから宛先、タイトル、本文などを指定できるので使いやすいのだ。今回は、このスクリプトがさらに実用的になるように改善していく。

HTML/XMLタグを扱えるようにする

clip2mail.ps1を使ってみるとわかると思うが、現状だと思ったようにメールの本文にテキストが入ってくれないことがある。例えば、次のテキストデータをご覧いただきたい。

  • XMLデータ

    XMLデータ

上記は、XMLドキュメントをメモ帳で開いたものだ。このテキストをコピーした状態でclip2mail.ps1を実行すると、次のような状態でメールコンポーザが起動する。

  • テキストがほとんどなくなってしまった新規メール

    テキストがほとんどなくなってしまった新規メール

XMLドキュメントのテキストがほとんど残っていない。

clip2mail.ps1で行っている処理を改めて考えてみよう。clip2mail.ps1では、本文に指定するテキストに含まれている空白を「 」へ変換している。次の処理だ。

$body=$body -replace " "," "

こうしないと、連続する複数の空白が1つの空白になってしまうからだ。

Thunderbirdのメールコンポーザは、HTMLの特殊文字を理解した上で本来の文字に変換して本文に貼り付けてくれる。この仕組みを利用して、空白を思った位置に貼り付けられるようにしている。

今回のケースもこれと同じことが起こったのだと考えられる。どうもXMLのタグがHTMLのタグとして解釈されて、先ほどのような結果になってしまったようだ。

それならば、タグをエスケープする方法を考えてみよう。単純に考えると、「<」と「>」というタグを表現する記号を、それぞれ特殊文字を使って「&lt;」と「&gt;」と表記してから渡せばよいのではないかと思う。

では、clip2mail.ps1でテキストを加工している部分に次の処理を追加してみよう。

$body=$body -replace "<","&lt;"
$body=$body -replace ">","&gt;"

実行すると、次のような状態でメールコンポーザが起動する。

  • XMLドキュメントが張り付いた状態のThunderbirdメールコンポーザ

    XMLドキュメントが張り付いた状態のThunderbirdメールコンポーザ

XMLドキュメントが想定通りにメール本文に使われるようになった。一歩前進だ。

タブを扱えるようにする

前回のclip2mail.ps1では、空白を特殊文字に変えてから本文として渡していた。

$body=$body -replace " ","&nbsp;"

感の良い方なら、嫌な予感がしていたかもしれない。空白の受け渡しに問題があるということは、タブに関しても似たようなことが起きる可能性が高い。

次のように、タブでインデントされたテキストデータを用意した。

  • タブでインデントされたソースコード

    タブでインデントされたソースコード

このテキストデータをシステムクリップボードにコピーしてからclip2mail.ps1を実行すると、次の状態でメールコンポーザが起動する。

  • 本文からタブが消えている

    本文からタブが消えている

本文からタブが消えている。やはり、タブはうまくThunderbirdのメールコンポーザに渡ってくれないようだ。

タブもHTMLでは特別な文字として処理される。では、特殊文字に変えれば問題が回避できるかと言えば、今回はそうはならなかった。タブは特殊文字で書いておいても消えてしまうのだ。

こういった場合に使えるのが、pre要素れある。pre要素内だとタブはタブとして使われることが多い。ただし、pre要素はブロック要素なので、pre要素を使うように書き換えるとタブの部分が改行してしまう。

この問題を解消するために、pre要素に特殊文字としてのタブを含めつつ、さらにCSSのスタイル指定を併用してpre要素をインラインで表示されるように変更する処理を加える。言葉にするとわかりにくいが、要するに次のようにタグを加工する処理を追加するわけだ。

$body=$body -replace "  ","<pre style='display:inline'>&#009;</pre>"

この処理を加えた状態で、先ほど同じようにclip2mail.ps1を実行してみよう。

  • タブが表示されるようになったThunderbirdメールコンポーザ

    タブが表示されるようになったThunderbirdメールコンポーザ

これで、タグとタブの双方を含んだテキストをclip2mail.ps1で扱えるようになった。

今回のPowerShellスクリプト

改めて、今回の改良をまとめたclip2mail.ps1が以下だ。

#!/usr/bin/env pwsh

#========================================================================
# システムクリップボードのテキストでメールを作成
#========================================================================

#========================================================================
# Thunderbirdアプリケーションパス
#========================================================================
$mailer='C:\Program Files\Mozilla Thunderbird\thunderbird.exe'

#========================================================================
# 本文の上限文字数
#========================================================================
$bodycharlimit = 32000

#========================================================================
# 宛先とサブジェクト
#========================================================================
$to=$env:DEFAULT_TO_EMAIL
$title="Windowsシステムクリップボード"

#========================================================================
# システムクリップボードのテキストをThunderbirdのコンポーザに貼り付け
# できるフォーマットへ変換
#========================================================================
$body=$(Get-Clipboard | Out-String)

$body=$body -replace " ","&nbsp;"
$body=$body -replace "<","&lt;"
$body=$body -replace ">","&gt;"
$body=$body -replace "  ","<pre style='display:inline'>&#009;</pre>"

#========================================================================
# 引数で指定できる文字列長には上限がある。上限を超えている場合には、条件
# 未満まで文字数を減らして使用する。
#========================================================================
if ($body.Length -gt $bodycharlimit) {
    $body = $body.Substring(0, $bodycharlimit)
}

#========================================================================
# メールを作成
#========================================================================
& $mailer                               `
    -compose                            `
    "to='$to',subject='$title',body='$body'"

前回のスクリプトに3行追加しただけだが、これで扱えるテキストファイルがさらに増えたことになる。ちょっとしたことだが、とても重要な変更だ。このように問題を洗い出し、一つ一つ潰していくことで、実用的なスクリプトに育てていくことができる。