2020年7月1日水曜日

Node.js の CGI で画像を添付したメールを送る

以前、CGI + Python で画像を添付したメールを送る という記事を書いたけど、たぶん Python の CGI の問題で 16KB 以上の画像ファイルの処理が難しい問題が出たため (後述)、Node.js で書き直してみました。


var express = require('express');
var app = express();
var multer = require('multer');
var upload = multer();


var https = require('https');
var fs = require('fs');
var serverOptions = {
  key:  fs.readFileSync('ssl/cert.key'),
  cert: fs.readFileSync('ssl/cert.crt'),
};
var port = 8888;


var mailer = require('nodemailer');
var mailerOptions = {
  service: 'Gmail',
  auth: {
    user: 'foo@bar.com',
    pass: 'password',
    port: 'port',
  }
};
var mailOptions = {
  from: 'foo@bar.com',
  to: 'to',
  subject: 'タイトル',
  text: 'text',
  attachments: [{ filename: 'hoge.png', content: 'content' }],
};

function sendEmail(req, emails) {
  var [lastName, firstName] = req.body.name.split(' ');
  mailOptions.to = req.body.email;
  mailOptions.text = `${lastName}さん、こんにちは。`;
  mailOptions.attachments[0].content = req.file.buffer;

  var smtp = mailer.createTransport(mailerOptions);
  smtp.sendMail(mailOptions, function(err) {
    if (err) console.log(err);
    smtp.close();
  });
}


app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use('/', express.static('public'));
app.post('/send', upload.single('img'), (req, res) => {
  sendEmail(req, emails);
  res.send('ok');
});
var server = https.createServer(serverOptions, app);
server.listen(port);
// app.listen(port);
クエリパラメータで、 name = [氏名] & to = [送信先] & img = [画像データ] を CGI 経由で POST で受け取り、Gmail でメール送信する例です。 画像データは、<input type="file"> や canvas.toBlob() を FormData.append() すると良いでしょう。 画像は昔なら base64 化して送ってましたが、今は canvas.toBlob() が良いです。 ちなみに Gmail でこのスクリプトを動かすためには、Google アカウントの セキュリティ設定 から、アプリパスワードの設定が必要です。


冒頭で述べた Python の CGI の問題ですが、私も正確にはわかってません。 症状としては画像が16KB を超えるとデータがカットされてしまい、画像が一部分しか送れない問題が見つかりました。 つい最近まで普通に動いていたのでまったく理由がわからず、途方に暮れました。 私のコードのバグではなく、OpenSSL か CGI の実装の問題とは思いますが、正直あまり深入りしたくない…。 Python の CGI ってデバッグが面倒で、サーバと CGI が分離していてデバッグしにくいし、OpenSSL のオプションがごった煮だし、使っている人少なそうな問題があります。 上記のコードを見てもわかるように、Node.js だと超いい感じに書けるので、よくできていると思います。 今後 CGI を書く人は Node.js がおすすめ。

0 件のコメント: