見出し画像

Googleスプレッドシートのリストからメールを自動送信する(個別添付ファイル付き)

はじめに

今回はGoogleスプレッドシートのリストから添付ファイルを個別に生成して自動でメールを送る方法をご紹介します。
Googleスプレッドシートで顧客情報を管理している場合もあると思います。100件近くなってくるとメールの送付もそこそこ手間になってきますので、そういった場合にこの方法を使うと非常に便利です。大幅な時間削減になります。
メインはGASを使ったプログラミングになります。

仕組み

①顧客リストから明細取得
②PDF作成してDriveに格納
③メールに添付して送信

手順①シートの用意

用意するシートは4枚です。

  • 顧客リスト

  • 明細

  • 請求書テンプレ

  • オプション

顧客リストシート

【シート名】

  • 顧客リスト

【カラム構成】

  • A1:顧客番号(※1)

  • B1:氏名

  • C1:メールアドレス

  • D1:送信ステータス(※2)

※1.A列の顧客番号は整数以外でも明細シートとの整合性が取れれば何でも問題ありません。(a1011とか)

※2.D列の送信ステータスはプログラムで自動的に入力されるので空白で構いません。

サンプルイメージ

注)赤枠の部分は後ほどコードに貼り付けるので控えておいてください。

明細シート

【シート名】

  • 明細

【カラム構成】

  • A1:顧客番号

  • B1:品目

  • C1:数量

  • D1:単位

  • E1:単価

  • F1:請求年

  • G1:請求月

※請求年と請求月はいずれも整数のみで入力してください。

サンプルイメージ

明細は逐次蓄積されることを想定しているため、次月以降の明細が入っていても問題ありません。↑の例では2023年12月に請求する場合は、請求月が12の明細に限定されますので2024年1月以降のログは除外されます。

請求書テンプレシート

【シート名】

・請求書テンプレ

テンプレートはこちらのサイトからダウンロードして利用しています。

サンプルイメージ

これは請求書に限らずテンプレートを変えることであらゆる資料に対応できます。

オプションシート

メール送信におけるオプションを設定します。

【シート名】

  • オプション

【カラム構成】

  • A1:送信元メールアドレス(※1)

  • A2:表示名

  • A3:メールの件名

  • A4:CC

  • A5:Bcc

  • A6:返信先アドレス

  • A7:本文ID(※2)

  • A8:請求書保存フォルダID(※3)

サンプルイメージ

※1.送信元メールアドレスはこのシートを作成しているGoogleアカウントに紐づいていれば、Gmail以外でも利用できます。
詳しくは↓の記事などを参考にしてみてください。

※2.次の手順②で用意する、GoogleドキュメントのIDをここに格納します。

※3.生成した請求書を格納するGoogle Drive上のフォルダIDです。下記手順で設定してください。

①フォルダの作成

請求書というフォルダを作成

②フォルダを開いてIDを取得→オプションシートのB8セルに貼り付ける

手順②返信用本文の用意

Googleドキュメントを使用して返信用の本文を作成します。

サンプルイメージ

※1.1行目の「〇〇様」はGASで挿入するのでそれ以降をここに記載してください。

※2.赤枠の部分はオプションシートのB7セルに貼り付けてください。

手順③コードを書く

GASを開く

スプレッドシートの拡張機能から「Apps Script」を選択

myfunctionを消す

赤枠がデフォルトで記入されてるので、一旦消去

コードを貼り付ける

↑で消したところに↓のコードをそのまま貼り付けます。

function exe(){
  const ss = SpreadsheetApp.getActive()
  const db = ss.getSheetByName("顧客リスト")
  const detailSh = ss.getSheetByName("明細")
  const tmp = ss.getSheetByName("請求書テンプレ")
  const opSh = ss.getSheetByName("オプション")
  const customers = db.getRange(2,1,db.getLastRow() - 1,db.getLastColumn()).getValues()
  const fromAdress = opSh.getRange(1,2).getValue();
  const fromName = opSh.getRange(2,2).getValue();
  const mailsubject = opSh.getRange(3,2).getValue();
  const cc = opSh.getRange(4,2).getValue();
  const bcc = opSh.getRange(5,2).getValue();
  const replyTo = opSh.getRange(6,2).getValue();
  const docId = opSh.getRange(7,2).getValue();
  const folderId = opSh.getRange(8,2).getValue();
  const text = DocumentApp.openById(docId).getBody().getText();
  let count = 0
  customers.forEach((customer,index) => {
    if(customer[3] == "" && count < 7){
      const detail = createDetail(detailSh,customer[0])
      detail.forEach(detail => {
        detail.splice(5,2)
        detail.splice(0,1)
        detail.splice(1,0,"","")
      })
      detailSh.getRange(15,1,14,4).clearContent()
      if(detail.length > 0){
        const name = customer[1]
        const subject = "御請求書の送付"
        const list = [
          [2,1,1,1,[[name]]],
          [6,2,1,1,[[subject]]],
          [15,1,detail.length,detail[0].length,detail]
        ]
        pasteSh(tmp,list)
        SpreadsheetApp.flush()
        const file = createPdf(folderId,ss.getId(),tmp.getSheetId(),`${name} 様 御請求書`)
        try{
          const email = customer[2]
          sendEmail(email,mailsubject,name,fromAdress,fromName,cc,bcc,replyTo,file,text) 
        }catch{
          db.getRange(index + 2,4).setValue("エラー")  
        }
        db.getRange(index + 2,4).setValue("済")
      }else{
        db.getRange(index + 2,4).setValue("請求なし")  
      }
      count += 1
    }
  })
}

function createDetail(sh,foreignKey){ 
  const allDetails = sh.getRange(2,1,sh.getLastRow() - 1,sh.getLastColumn()).getValues()
  const year = new Date().getFullYear()
  const month = new Date().getMonth() + 1
  const details = allDetails.filter(arg => {
    return arg[0] == foreignKey && arg[5] == year && arg[6] == month
  })
  return details
}

function pasteSh(sh,list){
  list.forEach(arg => {
    sh.getRange(arg[0],arg[1],arg[2],arg[3]).setValues(arg[4])
  })
}

function createPdf(folderId, ssId, shId, fileName){
  //PDFを作成するためのベースとなるURL
  const baseUrl = "https://docs.google.com/spreadsheets/d/"
    +  ssId
    + "/export?gid="
    + shId;
 
  //★★★自由にカスタマイズしてください★★★
  //PDFのオプションを指定
  const pdfOptions = "&exportFormat=pdf&format=pdf"
    + "&size=A4" //用紙サイズ (A4)
    + "&portrait=true"  //用紙の向き true: 縦向き / false: 横向き
    + "&fitw=true"  //ページ幅を用紙にフィットさせるか true: フィットさせる / false: 原寸大
    + "&top_margin=0.50" //上の余白
    + "&right_margin=0.50" //右の余白
    + "&bottom_margin=0.50" //下の余白
    + "&left_margin=0.50" //左の余白
    + "&horizontal_alignment=CENTER" //水平方向の位置
    + "&vertical_alignment=TOP" //垂直方向の位置
    + "&printtitle=false" //スプレッドシート名の表示有無
    + "&sheetnames=false" //シート名の表示有無
    + "&gridlines=false" //グリッドラインの表示有無
    + "&fzr=false" //固定行の表示有無
    + "&fzc=false" //固定列の表示有無;

  //PDFを作成するためのURL
  const url = baseUrl + pdfOptions;

  //アクセストークンを取得する
  const token = ScriptApp.getOAuthToken();

  //headersにアクセストークンを格納する
  const options = {
    headers: {
      'Authorization': 'Bearer ' +  token
    }
  };
 
  //PDFを作成する
  const blob = UrlFetchApp.fetch(url, options).getBlob().setName(fileName + '.pdf');

  //PDFの保存先フォルダー
  //フォルダーIDは引数のfolderIdを使用します
  const folder = DriveApp.getFolderById(folderId);

  //PDFを指定したフォルダに保存する
  const file = folder.createFile(blob);
  return file
}

function sendEmail(toAdress,subject,name,fromAdress,fromName,cc,bcc,replyTo,file,text) {   
  // オプションを設定する
  const option = {
    from:fromAdress,
    name:fromName,
    cc:cc,
    bcc:bcc,
    replyTo:replyTo,
    attachments:file
  }

  // メール本文を作成する
  const body =`${name}様\n${text}\n`

  // メールを送信する
  GmailApp.sendEmail(toAdress,subject,body,option)
}

手順④トリガーの設定

トリガーを押下

右下の「トリガーを追加」→設定

これで1分おきにプログラムが起動し、リストの中から未対応のユーザーにのみ処理を実行します。

1分おきにした理由は、APIのリクエスト上限によりPDFの連続作成に制限があるためです。7個以上だとエラーが発生します。そこで一回の実行につき7件に限定するため、定期的に呼び起こす必要があるのです。
尚、全件送り終えたらこのトリガーは削除してください。

手順⑤プログラム認証

初回の実行に限り認証が必要です。
↓の手順に沿って進めてください。

まとめ

以上でGoogleスプレッドシートのリストから個別PDFを生成、メールに添付して自動送信できるようになりました。
ぜひ一度お試しください。

この記事が気に入ったらサポートをしてみませんか?