Google Apps Scriptでメールを送信する - MailApp編【GAS】
2021年4月、新年度に入りこれまでどちらかというと中級編以上を取り上げてきましたが、Google Apps Scriptの入門編記事もいくつかつくってみようと思い、その中でもよく利用されるメール操作系を作ってみました。
今回はメール操作なので、送信やGMail自体の操作を中心にこれまでに自分がよく使ったものを中心に記述しています。
※以下、Google Workspaceについては、GWと省略
目次
今回使用するサンプルや資料
- mail操作サンプル - スプレッドシート
- MailAppクラス - Google Developer
- GmailAppクラス - Google Developer
はじめてGASに触れる人は、サンプルのスプレッドシートをコピーしてから、「ツール」→「スクリプトエディタ」で開いて編集をするようにしましょう。
また、Fromを書き換えての送信はGmailAppの側で対応してるのでそちらを利用するようにしましょう(但し、そのための手順というものが存在します)。
制限について
Google Apps Scriptは、様々なサービスを簡単に扱えますが、他のウェブサービス同様に実行には一定の制限があります。これは使いすぎや一部の人によってサービスを占有されるのを防ぐ為の処置であるので、回避は出来ません(上位のサービスを契約すれば緩和されたりはします)
今回のGASでのメールの操作に関しては以下のような制限が存在しますので、コードを記述する場合には意識して書く必要があります(GWアカウントについて記載)
- メールの送信制限 - GWアカウントの場合2000通/1日
- 宛先数制限 - GWアカウントの場合10000/1日(外部宛は3000/1日)
- メールの読み書き - GWアカウントの場合、50000件/1日
- 添付ファイルサイズ - GWアカウントの場合、1件あたり25MBまで
- 本文のサイズ - GWアカウントの場合、1件あたり400KBまで
メルマガなどで大量のメールを送ったりなどは、この制限に引っかかる可能性が高いです。また、添付ファイルのサイズなども引っかかる可能性が高い為、それらの目的で超えそうなケースは専用のアプリや外部サービスなどを利用すべきだと思います。
MailAppを使用する
MailAppはメールの送信だけ行えるもっとも基本的な機能です。Google Apps Scriptに触る上では最も基本中の基本になると思います。後述のGmailAppは送信だけでなくメールの中身を拾ったりできますが、通常はこのMailAppだけ扱えれば十分業務の自動化を実現可能です。
普通に送信してみる
普通にメール送信をするケース。もっとも基本的なものになります。しかし、基本が故に結構抑えるポイントは豊富にあります。以下のソースコードが基本になります。
//メールを送る(MailApp) function mailSend() { //メール本文を構築する var body = "お疲れ様です\n" + "今日は、パッションフルーツ専用培養土を開発しました。\n\n" + getnowdate(); //メールを送信する MailApp.sendEmail({ to: "ここにToでおくる送信先", cc: "CC送信先1, CC送信先2", bcc: "BCC送信先", subject: '新開発:パッション専用培養土について', name:"肥料開発部", body:body, }); }
- メール本文はBody変数に分けるのは、本文ゆえ長い文章になるので、別に切り分けておくのが定石です。
- メール本文内での改行は、バックスラッシュにnであるエスケープシーケンスを使う事で改行になります。
- もちろん、自分で作った関数などの返り値を本文等に含めることも可能です。
- MailApp.sendEmailで送信を行います。
- MailAppの中身は、toは必須。ccとbccは省略可能です。
- 送信先を複数設定したい場合には、""で囲った中で、カンマ区切りで複数設定すればOK
- subjectでメールタイトル。nameは省略すると既定の自分の名前が使われます。
このコードで送ると以下の図のような形で届きます。
図:これがもっとも基本的な送信方法
HTMLメールで装飾
前述のメールはテキスト形式のメールであるため、文字の装飾などは出来ません。現代のメールはHTML形式で使われるのが標準となっているので、このままでは、無味乾燥なメールとなります。そこでHTMLを使えるようにすると、文字の装飾が出来たり、より複雑なレスポンシブなメールを作るときには必須のオプションとなります。
//HTMLメールを送る function mailSend2() { //メール本文を構築する var body = "お疲れ様です<br>" + "今日は、パッションフルーツ専用培養土を開発しました。<br><br>" + "<font color='red'><b>" + getnowdate() + "</b></font>"; //メールを送信する MailApp.sendEmail({ to: "ここにToでおくる送信先", subject: '新開発:パッション専用培養土について', name:"肥料開発部", htmlBody:body, }); }
- Body本文内で、基本的なHTMLタグが利用可能です(何でも使えるわけではありません)
- 改行等は<br>タグなどで実現します。
- MailApp.sendEmailにてbodyではなく、htmlBodyをオプション指定に加える
このコードで送ると以下の図のようになります。また、応用をするとモバイルとPCとでメールの表示パターンを変えるレスポンシブメールも作ることが可能で、その際もhtmlBodyである必要があります。
図:文字の装飾がされ改行も自由自在
添付ファイルをつける
請求書などを生成後、PDF化してメールに添付して送るといったパターンは、ホワイトカラーの現場では非常に多いケースです。この添付ファイルもGoogle Apps Scriptで自動化して送ることが可能です。但し、Gmailはセキュリティ上添付できないファイル形式がありますので、注意は必要です(exeやzipなどが添付できません)
//メールにファイルを添付して送る function mailSend3() { //添付ファイルのID var attach1 = "ファイルのID"; //添付ファイルを取得する var blob = DriveApp.getFileById(attach1).getBlob(); //var blob2 = DriveApp.getFileById(attach2).getBlob(); //メール本文を構築する var body = "お疲れ様です<br>" + "今日は、パッションフルーツ専用培養土を開発しました。<br><br>" + "<font color='red'><b>" + getnowdate() + "</b></font>"; //メールを送信する MailApp.sendEmail({ to: "ここにメール送信先を指定", subject: '新開発:パッション専用培養土について', name:"肥料開発部", htmlBody:body, attachments:blob, //attachments:[blob,blob2] }); }
- 今回、複数添付の部分を見越してコードを記述しています(コメントアウトさせてあります)
- attach1変数に、Googleドライブ上の画像やPDFファイルのファイルIDを入れておきます。
- DriveAppのgetFileByIdにてattach1を指定して、Blob形式で取得させます。
- MailApp.sendEmailにてattachmentオプションを追加。Blob形式で取得したblob変数を指定する
- 複数の添付ファイルを付けたい場合には、attach2とblob2で追加取得させて、attachmentオプションでは、配列の形式でblobとblob2を指定してあげる
図:test2.pdfを添付してみた
インラインイメージ
前述では画像類などを添付ファイルとして付けましたが、そうではなくメール本文内に画像を埋め込みたい事があります。ちょっと複雑ですが、2つのオプションをよく見てhtmlBodyを構築する必要があります。
//インラインイメージでメールを送信 function mailSend4() { //インライン画像の指定 var inlineimage = "ファイルのID"; //画像をblobで取得する var blob = DriveApp.getFileById(inlineimage).getBlob(); //メール本文を構築する var body = "お疲れ様です<br>" + "今日は、パッションフルーツ専用培養土を開発しました。<br><br>" + "<img src='cid:sirakawa'>"; //メールを送信する MailApp.sendEmail({ to: "ここに送信先を入力", subject: 'ここにメールタイトル', htmlBody: body, inlineImages: { sirakawa: blob, //cidでsirakawaを名前で指定してるので } }); }
- inlineimage変数に、Googleドライブ上の画像やPDFファイルのファイルIDを入れておきます。
- DriveAppのgetFileByIdにてinlineimage変数を指定して、Blob形式で取得させます。
- img srcの指定ですが、メール本文内で、srcとしてcid:名前を指定する。今回はsirakawaという名前を使いました。
- 新たにinlineImagesオプションをMailApp.sendEmailに追加し、cidの名前と取得した画像のblobを指定します。
このコードで送ると、以下のように本文内で画像が展開されます。あまり使う機会は少ないと思いますが、例えばグラフを生成して表示させるといったケースで使えます。
図:本文内に画像を表示したい場合に使う
noReplyメール
GWアカウントでのみ使えるオプションで、よく外部サービスなどでも通知系のメールで使われてる返信先指定のないメールです。受信者に本メールに返信してほしくない場合に使います。この場合、送信元はnoreply@指定ドメインになります。
//noreplyメール function mailSend5() { //メール本文を構築する var body = "お疲れ様です<br>" + "今日は、パッションフルーツ専用培養土を開発しました。<br><br>"; //メールを送信する MailApp.sendEmail({ to: "ここに送信先メアドを入れる", subject: 'メール返信できません', htmlBody: body, noReply: true }); }
- MailApp.sendEmailにnoReplyオプションを追加し、trueを指定するだけ
これで送信すると以下の図のようになります。送信元メアドは表示されないので、返信が出来ません。
図:noreplyなので返信出来ません
返信先指定
通常は、メールの返信は送信元のFromで指定されてるメアドに対して行います。メールで返信時も自動でこの値を使ってToに入るようになっていますが、送信元に返信されてはちょっと困るケースで使うのが、返信先指定です。このオプションを使うことで、返信をクリックした時に、別の返信先のメアドが入るようになり、送信元ではない場所へ、受信者が意識せずに返信が可能です。
//replyToメール function mailSend6() { //メール本文を構築する var body = "お疲れ様です<br>" + "今日は、パッションフルーツ専用培養土を開発しました。<br><br>"; //メールを送信する MailApp.sendEmail({ to: "ここに送信先メアドを入れる", subject: '返信先は変えてありますよ', htmlBody: body, replyTo:"ここに返信先メアドを入れる" }); }
- MailApp.sendEmailに新たにreplayToオプションを追加し、返信先メアドを指定するだけ
見た目は通常のメールなのですが、返信をクリックすると、指定したメアドで新規メールが作られます。
図:返信先が追加され、Fromではないメアドが入ってる
メールがブロックされるケース
稀にMailAppからメールを送信する場合に於いて、相手先メールサーバからメールをブロックされることがあります。自分が遭遇したケースでは、GASのWebアプリのURLを貼り付けて送ったらブロックされてしまい、送れなかったことがあります(通常のメールはきちんと送れる)。
この場合解決法はMailAppを使うのではなく、GmailAppを利用して送信すると送れる場合があります。
図:ブロックされた事例
環境依存文字の文字化け
絵文字や漢字の特殊な文字(𠮷といった文字)などについて、Unicodeでも特殊な扱いになってる文字については、GmailApp.sendEmailで送信をすると�で表示され文字化けします。このメソッドが対応していないようです。送りたい場合はbase64でエンコードしてあげなければならない模様。
しかし、MailAppでの送信についてはこの問題が起きない為、こういった文字が入る場合には自前でエンコードするか?MailAppを使って送信するようにしましょう。
図:GmailAppだと文字化けする
制約事項
このように簡単にメールが送れるGoogle Apps ScriptのMailAppですが、いくつか現場の業務で使うには注意すべき点があります。
公式の送信制限
無制限に使いたい放題で、メールが送れるわけではありません。また昨今はメールの送信についてはかなり厳しい制約がついているため、例えばMailAppを使って大量のDMを送りつけるといったような用途で使った場合、あっという間にこの制限に引っかかって24時間送信できないBAN状態になることも報告されています。
公式サイト上での送信制限を見てみると、以下はGoogle Workspaceアカウントの場合ですが
- 1日あたりメール受信者数:1500通(つまり1日1アカウント、合計1500個宛までしかメールは送れません)
- 1日あたりドメイン内のメール受信者数:2000通(同組織内であっても、同様に2000個宛までしかメールは送れません)
- メール本文サイズ:400KBまで
- 添付ファイルサイズの上限:25MBまで
また、このほか、Google Apps Scriptの1回あたりの連続稼働時間6分の制約であったり、10秒間に2秒程度のウェイトを入れないと429エラーとなるといった制約(これは公式上には未記載)、これらを考慮して送信しなければならないので、メルマガ送信などには使わないほうが良いでしょう。
大量のメール送信を行う必要があるならば、外部のREST API対応の大量メール送信サービスを使うか?Google Cloud上にSendGridを構築して、そちらで行わせるなど別途仕組みが必要です。
※また昨今は、DKIM, DMARC設定が必須になったことに加えて、迷惑メール送信検知するとブロックされる可能性もあるだけでなく、同じGoogle相手の場合、迷惑メールフィルタによりゴミ箱直行する羽目になるので、オカシナ真似をGoogle WorkspaceのGmailで行うと厄介なことになります(メール上でメルマガ一発解除出来るようにする必要があるなどめちゃハードルがあります)。
1日100通制限
Google Workspace導入した直後、メールをGASで送信してると本来制約上は100通以上送れるハズなのに、100通でロックが掛かるという報告がちょいちょい新規導入組織から質問できます。
これはそもそも、まだ正式導入したとは言え、14日間の試用期間内の制限であり、即刻解除するためにはデポジットを支払う必要があります。他にもこの期間内は様々な利用制限が課せられているので注意が必要です。
1日のカウントリセットは日本時間の16時〜17時頃になります。
※なお、個人のGoogleアカウントの場合、そもそもGASでメール送信は1日100通までです。
Service invoked too many times for one day: email
GASでメール送信をしていたら、「Service invoked too many times for one day: email」というエラーが。これ正直ちょっと厄介な問題です。いくつかのパターンが考えられます。個人のGoogleアカウントではない且つGoogle Workspaceアカウントであり、支払いも相当期間終えてるので前述のような1日100通制限になっていないにもかかわらず、100通程度送ったらこのエラーで止まるというケースが報告されています。
想定されるパターンは以下の通り。
- 短時間での大量送信や迷惑メール検知でアカウントに対して制限が課せられている
- 前述のGoogle Apps ScriptのQuotaのなにかに引っかかって、クォータを食いつぶしてる
- GWSアカウントのつもりが、実行時に同時にログインしてる個人のGoogleアカウントを利用していた(本人気がついていない)
- メール送信件数は述べ人数であり、1500回送れるわけではない。宛先数が100件あり15回GASで送れば当然、Quotaに抵触する
- Utilities.sleepを入れずにそのまま大量送信して後ろで429エラーと同様のことが起きている
主にこのパターンです。なにがしかの自身の過失がほとんど原因なので、一個ずつ丁寧にしらべましょう。また、グループアドレスを活用するであったり、他の手段を考えるなど選択肢を変える必要もあるかもしれません。
そもそも、6分の制限がある以上、ループで1件ずつ送信を考えた時、Sleepを入れるならば1回の実行1通送るという想定では、送れるのはせいぜい200通までです。
制約状況の確認と回避方法
現時点でのメール送信制約状況を知る
1日1アカウント1500通までという制約で、現時点で枠がどれだけ残っているかは、GASで簡単に調べることが可能です。以下のコードを実行するだけです。MailAppのgetRemainingDailyQuotaというメソッドがそれに該当します。
既に何年も経過してるのに、この枠数が何もしていないのに100になってるようなケースが、前述のトラブルに該当します。
//送信枠の残確認 function myFunction() { console.log(MailApp.getRemainingDailyQuota()); }
図:何も使ってないので1500枠残ってる状況
制約回避のテクニック
当然、MailAppでここで1通送ればこの制約枠の残りは1499となります。しかし、この制約枠を回避するテクニックが存在します。それが「下書きとして作ってGmailAppで下書きを取得して送信させる」という絡め手。ただこの方法は当然手数が掛かるわけなので、1通送信に掛かる時間は余計に掛かります。
MailAppはメールを送信するだけのメソッドですが、GmailAppはGmailを操作するメソッドで上位互換の存在です。メールを送る以外の様々な操作が可能になっています。よってこの回避方法はMailAppを使わないという手法になるため、今回のブログテーマからはハズレます。
※勘違いしてはいけないのは、GmailAppで送るなら制約枠は消費しないわけじゃないということ。あくまでこの手法に限り制約枠が減らないというだけの話です。
//下書きを作ってからGmailAppで送るテクニック function mailDraftSend(){ //送信前残り枠チェック console.log(MailApp.getRemainingDailyQuota()) //メール本文を構築する const body = "お疲れ様です\n" + "今日は、パッションフルーツ専用培養土を開発しました。\n\n"; //送信先情報 const to = "ここに送信先メールアドレスを入れる"; const subject = "開発部通信"; //GmailAppで下書きとして保存する(下書きIDを取得する) const draft = GmailApp.createDraft(to, subject, body); const draftID = draft.getId(); //下書きを送信する GmailApp.getDraft(draftID).send(); //送信後残り枠チェック console.log(MailApp.getRemainingDailyQuota()) }
図:MailAppでそのまま送った場合
図:GmailAppで下書きにしてから送った場合
関連リンク
- Google Workspace における Gmail の送信制限
- Quotas for Google Services
- Google Apps Scriptを使ってメールの未読を一掃してみた
- Gmailに届いたメールをエイリアスごとに自動でタグを付けて分類してくれるGoogle Apps Scriptを使ってみた
- Download Gmail Messages as EML Files in Google Drive
- Macにおけるバックスラッシュ(\)の入力方法
- [Javascript] ゼロ埋め(ゼロパディング)する方法
- Message blocked when sending email from Google Script
- 【GAS,Gmail】一部環境依存文字が文字化けする
- Google Apps Script によるメール送信の落とし穴
- 「GASで1度に送信できるのは100通である」を検証する
- "Daily Usage" Quota is a per-project limit?
- 【GAS】メールの大量送信でエラー、1日のメール送信上限の確認方法、有償のGoogle Workspaceを利用しても送信上限が増えない理由
- 「Google Apps Scriptで頻発する『Service invoked too many times in a short time』エラー:短時間のAPI過剰呼び出しを解決するためのガイド」