vbs[001]VBScript で Gmail のテンプレートを作る

Google Chrome のアドレスバーに、
https://mail.google.com/mail/?view=cm&fs=1
と入力して[Enter]すると、Gmail が立ち上がる。
これを利用して Gmail のテンプレートを作ろう。

Chrome の起動時に、コマンドラインパラメータとして URL を渡すことができるので、下記コードを拡張子 .vbs で保存したファイルをダブルクリックして実行すると Gmail のテンプレートを立ち上げることができる。

Option Explicit
Dim newMail     '// https://mail.google.com/mail/?view=cm&fs=1
Dim mailTo      '// 宛先
Dim mailCc      '// CC
Dim mailBcc     '// BCC
Dim mailSu      '// 件名
Dim mailBody    '// 本文
Dim url         '// URL文字列全体
Dim userName    '// ログインユーザ名
Dim kanjiName   '// ログインユーザ漢字名
Dim familyName  '// ログインユーザ姓
Dim mobilePhone '// 携帯番号
Dim eMail       '// E-mailアドレス
Dim mobileStr   '// 署名(携帯番号)
Dim J           '// 改行×1
Dim JJ          '// 改行×2
Dim JJJ         '// 改行×3
userName = CreateObject("WScript.Network").UserName
kanjiName = GetStaffData(userName, 1): If kanjiName = "" Then kanjiName = "-- --"
familyName = Left(kanjiName, InStr(kanjiName, " ") - 1)
eMail = GetStaffData(userName, 2): If eMail = "" Then eMail = "--"
mobilePhone = GetStaffData(userName, 3)
If mobilePhone = "" Then
    mobileStr = ""
Else
    mobileStr = J & "携帯: " & mobilePhone
End If
'// "%0d%0a"=改行
J = "%0d%0a"
JJ = J & J
JJJ = J & J & J
newMail = "https://mail.google.com/mail/?view=cm&fs=1"
mailTo = "&to=府馬 一郎<fuba@foobar.com>"
mailCc = "&cc=保下 花子 <hogehanako@hogehoge.com>"
mailSu = "&su=[" & yyyymmdd & "]"
mailBody = "&body=フーバー株式会社 府馬様" & JJ & _
            "いつもお世話になっております。 ホゲホゲ株式会社 " & familyName & "です。" & JJJ & _
            "お忙しい中お手数ですが、よろしくお願い致します。" & JJJ & _
            "================================" & J & _
            "ホゲホゲ株式会社" & J & _
            "総務部" & J & _
            kanjiName & JJ & _
            "〒100-8111 東京都千代田区千代田1-1" & J & _
            "TEL: 03-3210-5678" & J & _
            "FAX: 03-3210-5679" & mobileStr & J & _
            "E-mail: " & eMail & J & _
            "================================" & J
url = newMail & mailTo & mailCc & mailSu & mailBody
Call OpenByChrome(url)
'_____________________________
Function yyyymmdd()
'// 今日の日付を yyyymmdd 形式の文字列で返す関数
    Dim nowStr
    nowStr = Year(Now())
    nowStr = nowStr & Right("0" & Month(Now()) , 2)
    nowStr = nowStr & Right("0" & Day(Now()) , 2)
'   nowStr = nowStr & Right("0" & Hour(Now()) , 2)
'   nowStr = nowStr & Right("0" & Minute(Now()) , 2)
'   nowStr = nowStr & Right("0" & Second(Now()) , 2)
    yyyymmdd = nowStr
End Function
'_____________________________
Sub OpenByChrome(url)
'// コマンドラインパラメータを指定して Google Chrome を起動する
    CreateObject("WScript.Shell").Run Chr(34) & GetChromePath & Chr(34) & " " & Chr(34) & url & Chr(34)
End Sub
'_____________________________
Function GetChromePath()
    Dim chromePath      '// Chrome本体のフルパス(x64)
    Dim chrome86Path    '// Chrome本体のフルパス(x86)
    chromePath = "C:\Program Files\Google\Chrome\Application\chrome.exe"
    chrome86Path = "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
    With CreateObject("Scripting.FileSystemObject")
        If .FileExists(chromePath) Then GetChromePath = chromePath: Exit Function
        If .FileExists(chrome86Path) Then GetChromePath = chrome86Path: Exit Function
    End With
    Msgbox "Chrome がありません。": WScript.Quit
End Function
'_____________________________
Function GetStaffData(user_name, clm)
    Dim i
    Dim stfArry(1, 3)
    stfArry(0, 0) = "taro_hoge": stfArry(0, 1) = "保下 太郎": stfArry(0, 2) = "hogetaro@hogehoge.com": stfArry(0, 3) = "080-1234-5678"
    stfArry(1, 0) = "hanako_hoge": stfArry(1, 1) = "保下 花子": stfArry(1, 2) = "hogehanako@hogehoge.com": stfArry(1, 3) = "080-1234-9876"
    GetStaffData = ""
    For i = LBound(stfArry) to UBound(stfArry)
        If stfArry(i, 0) = Lcase(user_name) Then GetStaffData = stfArry(i, clm): Exit For
    next
End Function

<1行目>
Option Explicit
は、変数の宣言を強制する命令である。
宣言されてない変数があるとコンパイルエラーになるのでプログラムのミスを見つけやすくなる。


<2~17行目>
プログラムで使う変数を宣言している。

VBScript では変数の型は指定しない。すべて Variant型として扱われるので、型を指定する構文もない。なので、VBAのように as String などと続けて書くとコンパイルエラーになる。
また、各変数は宣言時にそれが何を表しているのかをコメントしておくと後で読み返すときに理解しやすくなるし、コード本文中のコメントも節約できてすっきりしたコードになる。


<18~48行目>
各変数に値を代入している。

18~27行目はメールの送信者のデータで、userName をキーとして、スタッフデータの配列から漢字名や携帯番号などのユーザデータを抽出している。
なぜこういうことをするのかと言うと、スタッフデータ配列に登録されているスタッフであれば、誰がこのスクリプトを実行してもその人自身のデータ(署名など)がメールに反映されるようにするためだ。

CreateObject関数は、おそらく VBScript で最もよく使う関数と言ってよいだろう。この関数で様々なデータを取得できるのでぜひ使い慣れていただきたい。
ここでは、CreateObject("WScript.Network") でネットワークオブジェクトを生成し、その UserName プロパティで、スクリプトを実行するPCにログインしているユーザ名を取得している。

GetStaffData というのは、このプログラムのために独自に書き起こした関数(ユーザ定義関数)で、ログインユーザ名および2次元配列(スタッフデータ配列)の2次元目のインデックス(カラム)番号を引数にとり、配列に格納されているユーザ情報を返す。この関数自体のコードはプログラムの下方に記述してあり、他のコード中でいつでも呼び出すことができる。

このように、プログラムコードというのは関数を呼び出すコードがメインになる。
処理系が持っていない関数は新たに自分で書き起こすことになるが、汎用的で便利な関数を使いやすい形にしてまとめたものが、「ライブラリ」や「フレームワーク」と呼ばれるものだ。
オブジェクト指向におけるオブジェクトも元をただせば関数の集まりでしかなく、プログラミングとは「関数を書くこと]であると言ってもよい。

そもそも関数とは、ある入力に対して何らかの処理を施した結果を出力するものをいう。
プログラミングにおいては、入力に相応するものを「引数」、出力に相応するものを「戻り値」といい、この「引数→処理→戻り値」という一連の流れこそがプログラミングの基本中の基本。したがって、プログラミングにおいては、引数は何か、戻り値は何かということに常に気を配る必要がある。

この GetStaffData 関数で得たユーザ情報のうち、データがないものは "--" を出力し、データがないことを明示するようにしている。それによって出力データの異常がわかるのである。

20行目で familyName として漢字名から姓だけ取り出しているのは、メール本文冒頭の名乗りのためである。

なお、プログラムコードは通常ステートメントごとに改行して記述するが、「:」でつなぐことで複数のステートメントを1行で記述することができる。コードがわかりにくくなるのであまり使うことはないが、一つのステートメントがごく短い場合、コードの内容によっては1行で書いたほうが読みやすくなる場合もある。

22~27行目は、携帯番号を入れる変数 mobilePhone の値に、ユーザが携帯電話を持っている場合は携帯番号を、持っていない場合は空白を入れ何も表示しないように設定している。携帯番号は必ずしも署名欄に表示されなくてもよいので、明示的に "--" を出力する必要はない。

28行目以降は、送信するメールの情報である。
Chrome のアドレスバーに入力されるメールの文字列において、改行は %0d%0a と入力することになっている。
ただ、そのままだと読みにくいので、J という変数に入れ、2回改行や3回改行もそれぞれ JJ、JJJ としてコードが読みやすくなるようにしている。(28~31行目)

Gmail を立ち上げるために Chrome のアドレスバーに入力する文字列 https://mail.google.com/mail/?view=cm&fs=1 は必須だ。
それに続けて、&to= に続く文字列(メールアドレス)が宛先に、&cc= に続く文字列が CC に(BCC を入れたい場合は &bcc= に続ける)、&su= に続く文字列が件名となる。
件名の文字列に yyyymmdd とあるのは、その日の日付を yyyymmdd形式で返すユーザ定義関数を呼び出している。
VBScriptVBA のような Format関数を持っていないので、形式を指定して日付を取り出すには新たにコードを書き起こす必要がある。

メール本文の変数 mailBody に入れる文字列は長くなるので、本文が改行される位置でコード自体も改行して読みやすくしている。

newMail から mailBody までをすべてつなげた変数 url に代入されている文字列が、Chrome のアドレスバーに入力する文字列である。


<49行目>
コマンドラインパラメータを指定して Chrome を起動するユーザ定義関数を呼び出している。

実は、本プログラムのメインコードはこの1行だけと言ってもよい。
これまでのコードは単に変数に値を代入しているだけで、言わばおかずに過ぎない。
なので、変数をいくつも作って値を代入するような面倒くさいことはせずに、アドレスバーに入力する長~い文字列を OpenByChrome関数の引数として直接渡してもいいのだ。ただ、それだと極めて読みにくいコードになるし、何より署名等の表示データをユーザごとに自動的に変えることができない。

このスクリプトファイルのメインプログラムはこの行で終わりなので、以下はメインプログラムから呼び出すためのユーザ定義関数の記述となる。ひとつひとつ見ていこう。


<yyyymmdd関数>
今日の日付を yyyymmdd 形式の文字列で返すユーザ定義関数。引数はとらない。

nowStr = nowStr & Right("0" & Month(Now()) , 2) のような、A = A & B という記述は、自分自身に B を連結したものを自分自身に代入する、つまり自分自身に B が連結されるという意味である。

例えば VBScript において n = n + 1 という記述は極めてよく使われるが、これは変数 n を 1 増やすことを意味する。
これを「インクリメント」と言い、プログラミング言語によっては ++ や += などの「インクリメント演算子」が用意されている場合もある。(VBScript にはインクリメント演算子はない)

なお、VBScript の関数では yyyymmdd = nowStr のように、関数名と同名の変数に代入された値が戻り値として返される。


<OpenByChrome関数>
本プログラムの肝となるユーザ定義関数である。戻り値はない。
引数として渡された文字列をコマンドラインパラメータとして Chrome を起動させるために、CreateObject("WScript.Shell") の Run メソッドでシェルスクリプトWindowsコマンド)を実行する。

GetChromePath は、Chrome本体(実行ファイル)のフルパスを返す関数(後述)を呼び出している。
ただし、パスの文字列に空白が含まれているとうまく実行されないため、パスをダブルクォーテーションで囲っておく必要がある。
Chr() は、引数として渡された文字コードに対応するキャラクタを返す組み込み関数である。文字コード34が渡されるとダブルクォーテーション( " )を返す。


<GetChromePath関数>
Chrome本体(実行ファイル)のフルパスを返すユーザ定義関数。引数はとらない。
通常のインストールでは、64bit版と32bit版とでパスが異なるため、どちらかのパスで見つかった場合に関数を抜けるようにしている。
そのため、それ以外の特殊なパスにインストールされている場合はエラーメッセージを表示しプログラムが終了するようにしているので、その場合は特殊なパスを返すようにコードを書き換えればよい。

なお、VBScript には VBA が持っている Dir関数がないため、ファイルの存在判定は CreateObject("Scripting.FileSystemObject") の FileExistsメソッドで行う。

ちなみに、CreateObject("Scripting.FileSystemObject") という文字は長いので fso というオブジェクト変数に入れる人が多いが、私は With で括る派で、オブジェクト変数の宣言と代入はできるだけ避けたいのである。とくに理由はない。

Exit は、指定したコードブロックから抜けるためのステートメントである。
ここでは、Chrome のパスが見つかったら関数を抜けるように Function を指定している。抜けた後はその関数のコードは実行されない。

WScript.Quit はプログラム全体を終了させるコードである。VBAでは End ステートメントがそれにあたる。
Chrome のパスが見つからなくて Exit Function が実行されず関数を抜けることができなかった場合は WScript.Quit が実行されてプログラムが終了する。
Exit は指定したブロックを抜けるだけなのでメインプログラムの残りのコードは実行されるが、WScript.Quit はプログラム自体を終了させるのでそのあとは何も起こらない。


<GetStaffData関数>
スタッフデータの2次元配列から各要素を返すユーザ定義関数。
第1引数にログインユーザ名、第2引数に配列の2次元目のインデックス番号を指定する。
本プログラムにおいては[ログインユーザ名][漢字名][メールアドレス][携帯電話番号]の4つのデータをそれぞれ2名分用意し、2行4列の配列としているが、この配列データはいくらでも増減することができる。ただし、宣言している配列変数の最大インデックス番号も変更する必要がある。

配列データが膨大な場合は別ファイルとして読み込ませる方法もあるが、この程度の配列データであればコードの中に組み込んでプログラムを完結させたほうがリンク切れの心配もないのでエラーに強くなる。


<変数の初期化について>
今回のプログラムでは、BCCの値を入れるための変数 mailBcc を宣言しているが、この変数は宣言以降一度も使われていない。
プログラミング言語によっては、宣言した変数を初期化(初期値を与える)しないままプログラムを実行するとエラーになる。
VBScript の場合は、変数宣言時にデフォルト値(Empty)で初期化してくれるので、宣言された変数が使われなくてもエラーにはならない。本プログラムではそれを示すために使わない変数の宣言をあえて残しているが、コードがわかりづらくなるので使わない変数は宣言しないほうが良い。


VBScript の利点>
なにもわざわざ VBScript で書かなくても Gmail のテンプレートを作る方法など他にいくらでもある。
それでも VBScript で作る利点は何かというと、これを他のプログラムから呼び出すことができる、ということである。
例えば、タスクスケジューラなどで決まった時間にこのテンプレートが立ち上がるようにすることもできるし、コードを少し修正するだけで VBA に埋め込むこともできるので、Excel に登録されているメールアドレスなどのユーザ情報をそのまま使うことができるのだ。


<プログラミングの学習方法>
プログラミングの学習において最も効率的な方法は、人が書いたプログラムを参考に、変数の値やコードの一部を書き換えてみてどういう出力が得られるのか、エラーが出るのか出ないのか自分で確かめてみることだ。当然わからないことがいろいろと出てくるので、それをインターネットや図書館などを利用して自分で調べることが大事なのである。むろん、コンピュータが暴走しないように注意する必要はあるが、PCの1台や2台壊すぐらいの経験がないと良いプログラマにはなれないのである。(笑)
※注:私自身はコンピュータを壊すようなプログラムを書いたことはないので良いプログラマではない。

上で書いたコードも、商用私用を問わず、改変・配布等自由に行っていただいて構わない。ただし、それによっていかなる被害を被ったとしても当方に一切の責任はないものとする。


<例外処理について>
このプログラムは、コードをメモ帳にコピぺして拡張子.vbsで保存すれば[当方の環境においては]動くことを確認済みである。
が、読みやすさを優先するために例外処理(エラートラップ)コードをほとんど書いていない。
プログラムコードというものは例外処理を書いてなんぼである。例外処理のないコードはだめなコードだ。
なので、このプログラムを実行してエラーが出た場合は、ぜひそのエラーを回避する例外処理を組み込むことに挑戦していただき、エラートラップの難しさを体感してほしい。