こんばんは、@0yanです。
今日は経営企画のお手伝いで、宛先一人ひとりに本文が微妙に違うメールをGmailで一斉送信するためのコードを書きました。
JavaScriptもGASも初心者かつ滅多に触らないので多少苦労しましたが、良い機会だったので、それぞれの言語の備忘録も兼ねて記事にまとめることにしました。
同じことをやりたい人のお役に立てば幸いです。
やりたかったこと
スプレッドシートに
- 名前
- 会社名
- 送信URL
そのうえでスクリプトを実行すると、下図赤枠部分が宛先毎に異なるメールを一斉送信できる・・・これがやりたかったことです。
コード全体像
先にコード全体を提示してしまいます。
function sendQuestionnaire() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('シート1');
const dataRange = sheet.getDataRange();
// 名前、会社名、E-mail、送信用URLの列数を取得(列数固定だと、列数が変わったときに機能しなくなるため)
let nameIndex = 0;
let companyNameIndex = 0;
let emailIndex = 0;
let sendUrlIndex = 0;
for (var i = 1; i <= dataRange.getNumColumns(); i++) {
switch (sheet.getRange(row=1, column=i).getValue()) {
case '名前':
nameIndex = i -1; // 二次元配列のループは0から始まるため、列数を -1 する(以下同様)
case '会社名':
companyNameIndex = i -1;
case 'E-mail':
emailIndex = i -1;
case '送信URL':
sendUrlIndex = i -1;
default:
;
}
}
// E-mail送信
const subject = 'アンケートご協力のお願い';
const data = dataRange.getValues();
for (var i = 1; i < dataRange.getNumRows(); i++) {
let name = data[i][nameIndex]; // 0行目はヘッダー情報のためスキップ(以下同様)
let company = data[i][companyNameIndex];
let email = data[i][emailIndex];
let sendUrl = data[i][sendUrlIndex];
// メール本文
let body = `
${company}
${name}様
お世話になっております。
この度、${name}様の率直なお気持ち、ご意見を頂戴したく、
アンケートにご協力頂きたく存じます。
【アンケートURL】
${sendUrl}
何卒宜しくお願い申し上げます。
`
try {
GmailApp.sendEmail(email, subject, body, options={from: 'abc@gmail.com', bcc: 'xyz@gmail.com'});
console.log('送信OK: ${name} ${company} ${email} ${sendUrl}');
} catch (e) {
console.log('送信NG: ${name} ${e.name} ${e.message}');
}
}
}
##コード詳細
###序盤
- JavaScriptの関数定義は
function 関数名(引数) { 処理 }
- JavaScriptでは、データ型の定義しない
- 変数も関数も小文字から始まり、ローワーキャメルケースで記述
- 変数宣言は
var
,let
,const
のいずれかから始まる-
var
・・・再宣言OK、再代入OK -
let
・・・再宣言NG、再代入OK -
const
・・・再宣言NG、再代入NG
-
- GoogleスプレッドシートをGASで操作する際のざっくりとした段取りは以下のとおり
- Spreadsheetインスタンス生成
- SpreadsheetインスタンスからSheetインスタンス生成
- SheetインスタンスからRangeインスタンス生成
- RangeインスタンスからgetValuesメソッドで二次元配列生成
function sendQuestionnaire() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('シート1');
const dataRange = sheet.getDataRange();
###中盤
- JavaScriptのfor文は
for (var i = 1; i <= n; i++) { Trueの処理 };
- Rangeインスタンスから行数/列数を取得するには
getNumRows
メソッドとgetNumColumns
メソッド - JavaScriptにはswitch文がある(構文は以下のとおり)
- JavaScriptでフロー制御文中、何もしないときは
;
だけ書く - GASは行も列もインデックスが1から始まるが、二次元配列は0からなので厄介
// 名前、会社名、E-mail、送信用URLの列数を取得(列数固定だと、列数が変わったときに機能しなくなるため)
let nameIndex = 0;
let companyNameIndex = 0;
let emailIndex = 0;
let sendUrlIndex = 0;
for (var i = 1; i <= dataRange.getNumColumns(); i++) {
switch (sheet.getRange(row=1, column=i).getValue()) {
case '名前':
nameIndex = i -1; // 二次元配列のループは0から始まるため、列数を -1 する(以下同様)
case '会社名':
companyNameIndex = i -1;
case 'E-mail':
emailIndex = i -1;
case '送信URL':
sendUrlIndex = i -1;
default:
;
}
}
###終盤
- 前述のとおり、GASでRangeインスタンスから値を二次元配列で取り出したいときは
Range.getValues
メソッド - JavaScriptのテンプレート文字列は便利。Pythonのf文字列と似てる
- GASでメール送信は
GmailApp.sendEmail
メソッド- 第一引数:宛先メールアドレス
- 第二引数:件名
- 第三引数:本文
- 第四引数:オプション(下記以外にも添付ファイル等、色々ある模様)
- fromオプション:エイリアスが複数ある場合に送信元を指定
- Bccオプション:Bccを指定
-
Console.log
メソッド書いておくと、Apps Scriptの画面でログ見れて非常に便利(デバッグ中の表示が遅いのはめっちゃイライラするけど)
// E-mail送信
const subject = 'アンケートご協力のお願い';
const data = dataRange.getValues();
for (var i = 1; i < dataRange.getNumRows(); i++) {
let name = data[i][nameIndex]; // 0行目はヘッダー情報のためスキップ(以下同様)
let company = data[i][companyNameIndex];
let email = data[i][emailIndex];
let sendUrl = data[i][sendUrlIndex];
// メール本文
let body = `
${company}
${name}様
お世話になっております。
この度、${name}様の率直なお気持ち、ご意見を頂戴したく、
アンケートにご協力頂きたく存じます。
【アンケートURL】
${sendUrl}
何卒宜しくお願い申し上げます。
`
try {
GmailApp.sendEmail(email, subject, body, options={from: 'abc@gmail.com', bcc: 'xyz@gmail.com'});
console.log('送信OK: ${name} ${company} ${email} ${sendUrl}');
} catch (e) {
console.log('送信NG: ${name} ${e.name} ${e.message}');
}
}
}
#最後に
コートはこちらにもアップしました。
JavaScript & GAS初心者なので細かく書きました。
これを機に両言語とも避けないで使っていこうかな・・・と思います。