※この記事は、「Google Apps Script プログラミング (3) Gmail を使ってメールを送る」の続きです。
前回は、Gmail アカウントを使ったメール送信を行いました。今回はこれまで学んできたことを応用して、複数の人に一斉にメールを送るようにします。
コンテンツ
今回のゴール
シート上で、送信対象にチェックを入れている人に対して、メールを送信する予定のプログラムを作ります。
※実際には存在しないメールを用いていますので、送信の一歩手前の実行ログ確認までです。ご承知おきください。
ここで、実現している機能は、以下の通りです。
- シート上のデータから、送信対象にチェックが入っている人の「名前」と「メールアドレス」を取得する
- 取得したデータを使って、対象者にメールを送信する
(1) 準備をします
1) 元となるデータをダウンロードします
今回の練習をするための、元となるデータを用意します。以下のリンクをクリックして「akoroushi.csv」をダウンロードしてください。
このファイルは、CSV形式のファイルです。CSV とは Comma-Separated Value (カンマで区切られた値)という意味です。ダウンロードした akoroushi.csv を Windows の「メモ帳」で開くと、カンマで区切られた値が入ったデータになっていることが分かります。
2) CSVファイルを Google スプレッドシートに取り込みます
前回使用した Google スプレッドシートのシートの情報は空欄です。ここに、CSVファイルの内容を取り込みます。[ ファイル ] から [ インポート ] を選びます。
インポートするデータを選択します。手元にダウンロードした akoroushi.csv を入れ込みますので、[ アップロード ] を選択してください。
[ アップロード ] の枠の中に、akoroushi.csv をドラッグして入れます。
インポートの方法を、以下の通り指定します。
- 場所のインポート
現在のシートに追加する - 区切り文字の種類
カンマ - テキストを数値、日付、数式に変換
はい
ファイルをインポートし終えると、以下のような表示になります。
名前・メールアドレス・送信対象が表示されます。
※メールアドレスは架空のもので、存在しません。ご注意ください。
送信対象は TRUE (真) と FALSE(偽) のいずれかになっています。このような真偽いずれかの値を持つデータの型式のことを「ブーリアン型(ブール型・論理型)」と言います。これは、主に「チェックボックス」にチェックの有無と同様に扱われますので、見た目もチェックボックスにしてしまいましょう。
表計算ソフトでは、シート上にある一つひとつのデータ枠のことを「セル」と呼びます。セル C2~C9 の範囲を選択してから、[ 挿入 ] → [ チェックボックス ] を選ぶと、TRUE / FALSE がチェックボックスでの表示に変わります。
(2) チェックが入っている人の情報をまとめます
1) 前記事終了時点のコードを確認します
前記事 Google Apps Script (3) が終わっている時点では、以下のようになっています。
function myFunction() {
const sheet = SpreadsheetApp.getActiveSheet();
for(let num = 1; num <= 3; num++){
let message = "これは" + num + "回目のテストメッセージです";
sheet.getRange(num,1).setValue(message);
}
}
function sendEmail() {
const okurisakiAddress = "milldesign08@gmail.com";
const honbun = "こんにちは、これはプログラムを使って送信したメールです";
const kenmei = "連絡:初めてのメール";
GmailApp.sendEmail(okurisakiAddress, kenmei, honbun);
}
これから、myFunction() の中を書き換えていきましょう。
2) 全データをまとめて取得します
シート上のデータを、まとめて取得します。myFunction() の中身 を、このように書き換えましょう。書き換えるのは3行目から13行目の箇所です。
function myFunction() {
const sheet = SpreadsheetApp.getActiveSheet();
const data = sheet.getDataRange().getValues();
let akoName = "";
let akoEmail = "";
Logger.log(data);
/* ここから先はコメント扱いにしておきます
for(let num = 1; num <= 3; num++){
let message = "これは" + num + "回目のテストメッセージです";
sheet.getRange(num,1).setValue(message);
}
*/
}
- 3行目
シート上のデータを全てを取り出して、配列 data に入れます。 - 4行目
チェックの入っている人の名前を入れる変数 akoName を宣言しています。 - 5行目
チェックを入っている人のメールアドレスを入れる変数 akoEmail を宣言しています。 - 6行目
配列 data の中身を、実行ログに出力します。 - 8行目 と 13行目
/* から始めて */ で終えると、その間に囲まれたものをコメント扱いにして、プログラム実行の際に無視させます。この操作のことを「コメントアウト」と言います。コメントは、後になってプログラムを読み返す際に、自分自身や他者に何を目的で書いているのか、分かりやすくする目的で書きます。ここでは、後になって再利用するものなので、記述を残しているのです。
それでは、「myFunction」を「▷実行」します。
※前記事の最後に実行したのは、「sendEmail」でしたから、実行する関数を「myFunction」に切り替えてから実行しましょう。
実行すると、以下のような表示になります。
3) 配列とは
実行ログに、何やら長く情報が載りました。つい先程見た、akoroushi.csv に中身が似ています。これは「配列」というデータ構造の中に、シート上のデータを取り込んだからです。これを少し整理して、下に表示してみます。
実行ログの情報は、データ全体及び 1行分のデータが [ ] で囲まれています。また、列ごとのデータの区切りには , が使われています。これらは配列の中での枠の区切りを示しています。
配列 data の構造を見ると、先程の枠の区切りに基づいて、取り込んだデータを data[0][0] から始まって data[8][2] までの枠に収めているのです。例えば、「大石主税」を取り出す場合は、data[2][0] と示します。
この時に使う[] 内の数値のことを、インデックス(index・添字)と言います。この数字を有効に使って、「全ての行で、『送信対象』のチェックが入っている(TRUEである)人の情報を取り出す」操作をします。
4) for の繰り返しを使って必要な情報をまとめます
それでは、プログラムを以下のように書き換えてみましょう。
function myFunction() {
const sheet = SpreadsheetApp.getActiveSheet();
const data = sheet.getDataRange().getValues();
let akoName = "";
let akoEmail = "";
const lastRow = data.length - 1;
for(let num = 1; num <= lastRow; num++){
if(data[num][2]){
akoName = akoName + data[num][0] + "\n";
akoEmail = akoEmail + data[num][1] + ",";
}
}
Logger.log(akoName);
Logger.log(akoEmail);
}
- 6行目
データ全件の行数を 変数 lastRow に入れています。data.length とは、配列内の行データの数です。ここでは [0] ~ [8] までの 9行分で「9」と求められますが、実際には[0] は見出し行で、データは [8] までなので、9 – 1 = 8 を、lastRow に入れています。 - 8行目
num が 1から、変数 lastRow 以下(8以下)の間、繰り返す宣言をしています。 - 9行目
if文です。ifの中に条件式を入れて、条件式が TRUE だった時に { } 内の処理(10行目と11行目)を行います。今回の場合、data[num][2] が TRUE だった場合 (送信対象が TRUEだった場合、つまりチェックが入っている場合)と書いています。 - 10行目
9行目が TRUE だった際の、名前情報をまとめる処理です。
名前は、data[num][0] に入っています。これを取り出して、変数 akoName につなぎ合わせています。最後に書いてある「 \n 」は、「¥の半角文字」+「n」と入力します。これは「エスケープ文字」と呼ばれているもの一つで、「\n」は改行を示します。 - 11行目
9行目が TRUE だった際の、メールアドレス情報をまとめる処理です。
メールアドレスは、data[num][1] に入っています。これを取り出して、変数 akoEmail につなぎ合わせています。 - 14行目
変数 akoName の値を、実行ログに出力します - 15行目
変数 akoEmail の値を、実行ログに出力します
実行結果は、以下の通りです。
チェックの入っていた 5名の名前とメールアドレス情報を、取りまとめることが出来ました。
今度は、これを使って 機能 sendEmail() を動かす準備をしましょう。
(3) まとめた情報を使ってメールを送ります
1) sendEmail() のメール送信機能を止める
まずは、準備のため sendEmail() の一部をコメントにしておきましょう。
function myFunction() {
const sheet = SpreadsheetApp.getActiveSheet();
const data = sheet.getDataRange().getValues();
let akoName = "";
let akoEmail = "";
const lastRow = data.length - 1;
for(let num = 1; num <= lastRow; num++){
if(data[num][2]){
akoName = akoName + data[num][0] + "\n";
akoEmail = akoEmail + data[num][1] + ",";
}
}
Logger.log(akoName);
Logger.log(akoEmail);
}
function sendEmail() {
const okurisakiAddress = "milldesign08@gmail.com";
const honbun = "こんにちは、これはプログラムを使って送信したメールです";
const kenmei = "連絡:初めてのメール";
/* 誤ってメールを送らないように、コメントにします。
GmailApp.sendEmail(okurisakiAddress, kenmei, honbun);
*/
}
23行目から25行目の内容を、まとめてコメントにしました。存在しないメールアドレスに対してメールを送信するのを防ぐためです。
2) sendEmail() へチェックした情報を渡す
myFunction() で「チェックの入った人の情報を取りまとめた」ので、これを sendEmail() に渡します。myFunction() の一部と、sendEmail() の一部を、以下のように書き換えます。
function myFunction() {
const sheet = SpreadsheetApp.getActiveSheet();
const data = sheet.getDataRange().getValues();
let akoName = "";
let akoEmail = "";
const lastRow = data.length - 1;
for(let num = 1; num <= lastRow; num++){
if(data[num][2]){
akoName = akoName + data[num][0] + "\n";
akoEmail = akoEmail + data[num][1] + ",";
}
}
sendEmail(akoEmail, akoName);
}
function sendEmail(okurisakiAddress, member) {
const honbun = "12月14日は、吉良邸への討ち入りです。\n\n" + "■表門担当者\n" + member;
const kenmei = "連絡:討ち入り日程について";
Logger.log(honbun);
Logger.log(okurisakiAddress);
/* 誤ってメールを送らないように、コメントにします。
GmailApp.sendEmail(okurisakiAddress, kenmei, honbun);
*/
}
- 14行目
myFunction() の中から、sendEmail() を呼び出しています。その際に、sendEmail(akoEmail, akoName) と書くことで、変数 akoEmail と 変数 akoName を渡しています。
sendEmail() 実行後は、この行に再び戻ってきます。 - 17行目
14行目で、sendEmail() を実行するために変数 2つが指示されたので、それに合わせて 機能を拡張します。ただし、この sendEmail() の中では、受け取ったものをそれぞれ okurisakiAddress、member という名前で扱います。- okurisakiAddress … 受け取った akoEmail の値を示しています
- member … 受け取った akoName の値を示しています
- 18行目
変数 honbun (メール本文)を決めています。討ち入り日程に関する情報です。チェックの入った人の名前は、■表門担当者 として、メール本文中に記載されます。 - 19行目
それっぽい件名にしています。深い意味はありません。 - 21行目
変数 honbun の値を、実行ログに出力します - 15行目
変数 okurisakiAddress の値を、実行ログに出力します
それでは、「myFunction」を「▷実行」します。
このように、メールを送信する準備までが整いました。GmailApp.sendEmail()を含むコメントを解除すれば、実際にメールが送信されます(しつこいようですが、今回は架空のアドレスですので、送信しません)。
小さなプログラムの積み重ねから
ゴールまでの間に、小さなプログラムを積み重ねていきました。Logger.log () を使いながら、実行ログを一つひとつ確認して進めてきました。
このように、小さなステップで確認しながら作っていくと、間違いに気づきやすいです。何度エラーを出してもよいので、少しずつ作っていきましょう。
(余談:今回は、赤穂浪士の名前を使いました。討ち入りの際に、表門隊・裏門隊の二手に分かれたことになっています。チェックしてみて分かったのですが、親子関係・兄弟関係にある二人が参加していた場合、例外なく分かれて配属されていたのでした。本当は、呪術廻戦のキャラクター名を使おうとしたのですが、内容に疎いので遠慮しました。)