誰かにファイルを送信する場合、今の世の中でも普通の人はフォーマットはCSVで方法はメールで欲しいというのがよくあります。スケジュールで自動的にGmailを使って添付メールを送りたかったのでNodemailer を使って書いてみました。本当はちゃんとした内容の添付ファイルなのですが、テスト用にランダム文字列をChance.js で生成しました。最近lodash が気に入っているので関数型言語っぽい書き方です。
プロジェクト 作成したサンプルプログラムはリポジトリ に置いています。
$ cd /node_apps/node-gmail $ tree -L 1 . ├── Dockerfile ├── README.md ├── app.js ├── config.json ├── config.json.original ├── docker-compose.yml ├── gmail.js ├── node_modules -> /dist/node_modules └── package.json
開発と実行はDocker Composeを使っています。カレントディレクトリに/dist/node_modules
へのシムリンクを作っておきます。/dist/node_modules
はDockerホスト内には存在しませんが、このディレクトリをコンテナにマウントしたときにコンテナ内で有効になります。
$ ln -s /dist/node_modules .
プログラム app.jsがエントリポイントになります。
/node_apps/node-gmail/app.js 'use strict' ;var _ = require ('lodash' ), json2csv = require ('nice-json2csv' ), mailer = require ('./gmail' ), Chance = require ('chance' ), chance = new Chance(), args = process.argv.splice(2 ), email = args[0 ], data = _.times(10 , function (n ) { return _.zipObject(_.map(['a' ,'b' ,'c' ], function (v ) {return [v,chance.name()]}))}); function prettyPrint (email ) { return _.compose(_.curry(mailer.sendWithAttachment)(email), json2csv.convert, _.map)} prettyPrint(email) (data, function (s ) {return _.pick(s,['a' ,'c' ])});
lodash を使ってなるべく変数を使わずに関数型言語っぽく書いてみました。プログラムの実行にはあまり影響はないです。Node.jsだとコールバックにfunctionとreturnの宣言が必要なのでちょっと長くなります。
ランダムな値をChance.js で作成してa
,b
,c
をキーに持つマップを10個作成します。
data = _.times(10 , function (n ) { return _.zipObject(_.map(['a' ,'b' ,'c' ], function (v ) {return [v,chance.name()]}))});
prettyPrint関数で生成する関数合成の最初の_map
では上記のdata
に_.pick(s,['a','c'])
を適用してa
とc
のキーと値だけ抽出しています。
prettyPrint(email) (data, function (s ) {return _.pick(s,['a' ,'c' ])});
関数合成では右から順に_.map
、json2csv.convert
、カリー化したmailer.sendWithAttachment
と評価されていきます。
添付ファイル付きのGmail app.js
で実行しているsendWithAttachment
関数はgmail.js
からmodule.exports
しています。
/node_apps/node-gmail/gmail.js 'use strict' ;var nodemailer = require ('nodemailer' ), validator = require ('validator' ), config = require ('./config.json' ), util = require ('util' ), moment = require ('moment-timezone' ); function createFilename ( ) { return moment(new Date ()) .tz("Asia/Tokyo" ) .format('YYYYMMDD-HHmmss' ) + '.csv' ; } function sendWithAttachment (gmail_to,content ) { console .log(content); if (! validator.isEmail(gmail_to)) { return console .log('--email is not valid: ' , gmail_to); } var transporter = nodemailer.createTransport({ service: 'Gmail' , auth: { user: config.gmail_user, pass: config.gmail_pass } }); var msg = { from : config.gmail_from, to: gmail_to, subject: config.gmail_subject, text: config.gmail_text, attachments: [ {filename : createFilename(), content: content} ] }; transporter.sendMail(msg, function (err ) { if (err) { console .log('Sending to ' + msg.to + ' failed: ' + err); } console .log('Sent to ' + msg.to); }); } module .exports.sendWithAttachment = sendWithAttachment;
添付ファイルの中身はcontent
変数に文字列としてCSVデータが入っています。config.json
にGmailの認証情報とメールの件名などの設定を記述して実行します。docker-compose run
を実行すると引数に指定したメールアドレスに添付ファイル付きのメールが送信されます。添付ファイルの内容は確認用に標準出力もしています。
$ docker-compose run --rm gmail -- ma6ato@gmail.com > node-gmail@0.0.1 start /app > node app.js "ma6ato@gmail.com" "a" ,"c" "Dean Luna" ,"Minerva Walker" "Dylan Richards" ,"Alvin Bryant" "Oscar Martin" ,"Norman Dean" "Elmer Long" ,"Leroy Phelps" "Caroline Hayes" ,"Lura Foster" "Belle Clarke" ,"Dora Bell" "Garrett McDonald" ,"Craig Grant" "Hester Silva" ,"Donald Harris" "Gertrude Boone" ,"Jennie Walsh" "Katherine Lee" ,"Carrie Wood" Sent to ma6ato@gmail.com Removing nodegmail_gmail_run_1...