情シス

[Google Apps Script]メールをemlとして保存する

今回の記事は「情シスSlack Advent Calendar 2019」の11日目の記事となります。

情シスSlackとは?

情シスSlackとは、yokoyama(@Ringo_o_7)さんが作成された、文字通り“情シス”の方向けのコミュニティで、Slackのワークスペースでは非常に多くのメンバーが活発に情報交換を行っています。

詳しくはyokoyamaさんの下記noteをご覧ください(丸投げ)。

私はこのnoteを拝読して、コミュニティに参加させていただくことにしました。

自己紹介

Slackの方では大した自己紹介はしていなかったので、ここで改めて簡単に自己紹介しておきます。

  • HN:きぬあさ ※由来は好きなゲームのキャラ
  • 業務:総務の中のIT担当的なやつです。備品調達からPC設定、ヘルプデスク、展示会対応など広く担当しております。一番得意なのは複合機の紙詰まり対応やトナー交換でしょうか。紙詰まった際に無理やり取ろうとして破れた紙の破片を、ピンセットでよく取り除いております。
  • 開発:業務ではコードはあまり書きませんが、自分が楽するためにバッチやVBS、PowerShellで簡単な処理を書くことはあります。令和になってもVBSの出番は多いです。会計ソフトから出力したCSVファイルを、お客様希望の形式に直すVBAマクロなんかも作成しております。

あと、2011年からこのようなブログを書いております。

今回のような記事と前回書いたような記事↓との落差が激しく、たまに「このブログ、何人で書いているの?」と聞かれることもありますが、すべて私一人で書いております。

アイカツ!プリキュアポケモンも好きで、書きたいことがあれば何でもこのブログに書きなぐっております。

アドベントカレンダー用のネタをどうしよう?

さて、ここから本題です。
アドベントカレンダーの記事を書くにあたり、どんな内容にしようかと考えました。

情シスSlackに参加されている方々の会話を見ると、ぶっちゃけ皆さんスゴイです。
Azure?AWS?Jamf??、オンプレ全開、未だにActiveXコントロールのメンテをしている私からすると、もはや別世界の会話です。

「こんな“つよつよ情シス”さんたちの参考になるようなネタって何かあったっけ?」と思うわけですが、Slackを眺めていると、どうやらGoogle Apps Script(GAS)を嗜まれている方も居られる様子。

よろしい、ならばGASネタだ!

kintoneを使われている方もいらっしゃるので、GAS × kintone、これならば割と参考になるんじゃないか?、そう考えてはみたものの、すぐ思いつくネタはもう書いていました↓

そもそも、私自身kintoneについて語れるほど詳しいわけではないという、致命的な弱点もあります。

・・・で、結局何にするか?

「うーん。まあ、メールだったら毎日使うし、メール周りの処理で何か書くか!」

というわけで、今回は“受信したメールをemlとして保存する処理”を書いてみようと思います。

eml化する理由は『会社で使っているメーラーがemlだと扱いやすいから』、という私的な事情からです。

メールをemlとして保存するスクリプト

eml化といっても難しい処理ではありません。
下記記事にある通り、「メッセージのソースを表示」から表示できるソースをテキスト形式で保存すれば良いだけです。

手作業で行う場合は、「メッセージをダウンロード」する方が簡単ですね。

スクリプトで書くと下記のようになります。

function myFunction() {
  //1. メッセージを取得
  var msg = GmailApp.getInboxThreads(0, 1)[0].getMessages()[0];
  //2. 取得したメッセージからblob取得
  var blob = msg2eml(msg);
  //3. ドライブにemlファイルとして保存
  DriveApp.createFile(blob);
}

//メッセージをeml(blob)として取得
function msg2eml(msg) {
  var fn = msg.getSubject().replace(/[:<>\*\?\"\\\/|]/g, "_") //ファイル名として使用できない文字を置換
    + "_" + Utilities.formatDate(msg.getDate(), "Asia/Tokyo", "yyyyMMddHHmmss");
  var blob = Utilities.newBlob(msg.getRawContent())
    .setName(fn + ".eml")
    .setContentTypeFromExtension();
  return blob;
}

GmailMessage.getRawContentメソッドで取得した文字列をblobにし、DriveApp.createFileメソッドでファイルとして保存しているだけです。

ファイル名はメールの件名をベースにしていますが、Windows上でファイル名として使用できない文字は「 _ 」(アンダーバー)に置換しています。

任意の期間に受信したメールをemlとして保存する

さすがに上記処理だけでは中々使う機会も無いので、もうちょっと発展させます。

//前月に受信したメールをemlとして保存
function myFunction2() {
  var blob, fol;
  var fol_name = "eml";
  
  //保存先フォルダ取得
  if (DriveApp.getFoldersByName(fol_name).hasNext() === false) {
    fol = DriveApp.createFolder(fol_name);
  } else {
    fol = DriveApp.getFoldersByName(fol_name).next();
  }
  
  //前月の月初と月末取得
  var d = new Date();
  d.setMonth(d.getMonth() - 1);
  d.setDate(1);
  var bom = Utilities.formatDate(d, "Asia/Tokyo", "yyyy/MM/dd"); //月初
  d.setMonth(d.getMonth() + 1);
  d.setDate(0);
  var eom = Utilities.formatDate(d, "Asia/Tokyo", "yyyy/MM/dd"); //月末
  
  var q = "after:" + bom + " before:" + eom;
  var threads = GmailApp.search(q);
  if (threads.length > 0) {
    threads.forEach(function(thread) {
      thread.getMessages().forEach(function(msg) {
        blob = msg2eml(msg);
        fol.createFile(blob);
      });
    });
  }
}

GmailApp.searchメソッドで検索条件を指定し、任意の期間に受信したメールをeml化する処理です。

上記コードでは、スクリプト実行時の前月のメールに対して処理を行っていますが、検索式(クエリー)には様々な演算子を指定できるので、送信者や受信者、件名等で絞り込みを行えます。

eml化した複数のファイルをZip形式の添付ファイルとしてメール送信する

折角なのでもうちょっと発展させ、eml化した複数のファイルをZip形式で圧縮して、メールの添付ファイルとして指定した宛先に送信する処理を書いてみます。

Utilities.zipメソッドを使えばファイルをZip形式で圧縮できますが、@tanaike氏が公開されているライブラリ「ZipFolder」(プロジェクトキーは下記)を使うと、フォルダごと簡単に圧縮することができます。

1q5FY5UxNpFNYxtd-LZgIjchicKq1BfDCVPbOwA0BDiL6zfCTxjfe-Puz

ライブラリの追加方法は下記サイトをご参照ください。

/*
  eml化した複数のファイルをZip形式の添付ファイルとしてメール送信
  「ZipFolder」ライブラリ( 1q5FY5UxNpFNYxtd-LZgIjchicKq1BfDCVPbOwA0BDiL6zfCTxjfe-Puz )要追加
  https://github.com/tanaikech/ZipFolder
*/
function myFunction3() {
  var blob, fol;
  var fol_name = "eml";
  var mail_to = "(メールの宛先)";
  
  //保存先フォルダ取得
  if (DriveApp.getFoldersByName(fol_name).hasNext() === false) {
    fol = DriveApp.createFolder(fol_name);
  } else {
    fol = DriveApp.getFoldersByName(fol_name).next();
  }
  
  //件名:セキュリティ 通知 のメールをemlとして指定したフォルダに保存
  var q = "subject:セキュリティ 通知";
  var threads = GmailApp.search(q);
  if (threads.length > 0) {
    threads.forEach(function(thread) {
      thread.getMessages().forEach(function(msg) {
        fol.createFile(msg2eml(msg));
      });
    });
  }
  
  //emlの保存先フォルダをZip圧縮 → 添付ファイルとしてメール送信
  var date = Utilities.formatDate(new Date(), "Asia/Tokyo", "yyyyMMdd");
  blob = ZipFolder.zip(fol.getId())
    .setName(date + "_eml.zip")
    .setContentTypeFromExtension();
  GmailApp.sendEmail(mail_to, "eml - " + date, blob.getName(), {
    "attachments": [blob]
  });
  DriveApp.removeFolder(fol); //使い終わった保存先フォルダを削除
}

注意点

上記のように、受信したメールをemlファイルとして保存できると、「メールアーカイブのように使えるんじゃないか?」、そう思われる方もいらっしゃるかもしれませんが、残念ながらそれは中々難しいです。

というのは、GASにはGmailの読み取り制限があり、上限を超えての処理ができなくなっているからです。

そして何より、GAS経験者であれば引っ掛かったことがある人も多いであろう『6分の壁』問題があるため、処理する件数が多ければ多いほど失敗する可能性も高くなります。

単にメールをバックアップすることだけが目的なのであれば、下記サイトのように標準機能を活用した方が良いでしょう。

ただし、GASにはトリガーという強みがあるので、これを活用することで、例えば“毎月1日の午前0時に前月に受信した特定のメールだけをZip圧縮して保存しておく”なんて処理もできるわけです。

おわりに

いかがでしたでしょうか?
今回はGoogle Apps Scriptでメールをeml化して云々、といったスクリプトを紹介しましたが、GASの弱点を考慮しつつ強みを生かせれば、活用する機会はあるのではないかと思います。

また、上でも書きましたが、@tanaike氏は非常ーーに便利なGASライブラリを多数公開されています。

これらのライブラリを活用すると面倒な処理を簡単に書けるようになるので、GASでコードを書かれる方は、氏のライブラリだけでも是非チェックしてみてください!

そして最後に、ここまで書いておいて何ですが、私の会社ではG Suiteを導入していないので、普段は全くGASを触る機会がありません。ぶっちゃけGASよく分かりません!!

・・・が、分からないなりに独学で、引き続き精進して参ります。
ここまでお読みいただき、どうもありがとうございました。

情シスSlack Advent Calendar 2019

2019年度の情シスSlack・アドベントカレンダーは第二段まであります。
読み応えのある記事ばかりですので、是非下記リンクからご覧ください。

関連記事

  1. Google関連

    [Google Apps Script]スプレッドシートで不要な空白文字を削除する

    スプレッドシートでは、「データ」メニューにある「空白文字を削除」を実行…

  2. Office関連

    Google スライドで新規プレゼンテーションを作成するVBAマクロ

    ここ数日PowerPointのマクロに加え、Google Apps S…

  3. Google関連

    [Google Apps Script]サイドバーを表示する

    Google Apps Scriptでサイドバーを表示します。…

  4. Google関連

    [Google Apps Script]jQuery UIのDatepickerを使ってスプレッドシ…

    「この記事のようにjQuery UIのDatepickerを使ってスプ…

  5. Google関連

    以前のGoogle マップを使う。

    「「新しい Google マップ」正式公開、地図大きく、精緻すぎる3D…

コメント

  • コメント (0)

  • トラックバックは利用できません。

  1. この記事へのコメントはありません。

Time limit is exhausted. Please reload CAPTCHA.

最近の記事

アーカイブ

RapidSSL_SEAL-90x50
PAGE TOP