Node.jsでメール送信を作ってみる。

Node.js を使用してメール送信クライアントを作ってみました。
とはいえ「 nodemailer 」という npm パッケージを使用しただけなので、
実装自体は特別苦は無いはず。
これを使えば、ラズパイからセンサーデータをメール通知させることもできるので、そのためのテスト。

目次

nodemailer 導入

プロジェクトのフォルダで、npm install nodemailer --save実行

これだけです。

単発でメールを送ってみる

nodemailer.comを参考に、
simplemailsend.js を作成します。

今回は、送信用の smtp サーバは gmail を使用します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
var Mailer = require('nodemailer');

//使用するSMTPサーバに関する設定
var Smtpsetting = {
//Webサービスを使う場合
service: 'Gmail',
secure: true,
auth: {
user: '[Gmailアドレス]',
pass: '[Gmailアカウントのパスワード]',
port: '465' //使用ポートGmailは465だった
}
};

//メールの内容
var Mailobject = {
from: '[送信元アドレス]',
to: '[送信先アドレス]',
subject: 'This mail is test.',
text: `
テストのメールです。
テストなので、返信不要です。
`, //テキスト形式のメール本文
html: `
<html>
<head>
</head>
<body>
<h1>テストのメールです</h1>
<p>テストなので、返信不要です。</p>
</body>
</html>
` //html形式のメール本文
};

//SMTP接続の作成
var Smtp = Mailer.createTransport('SMTP', Smtpsetting);

//メール送信を関数定義
let Send = () => Smtp.sendMail(Mailobject, function (err, res) {

if (err) {
//送信に失敗したとき
console.log('送信失敗\n=>' + err);

} else {
//送信に成功したとき
console.log('送信成功\n=>' + res.message);
}
//SMTP接続の切断
Smtp.close();
});

//メール送信
Send();

伏せてある Gmail アカウントの項目を埋めてあげ、
node .\simplemailsend.jsで実行します。

送信先に指定したアドレスにメールが送信できたはずです。
送信先を Gmail にしていたのですが、html 形式表示されました。
メールクライアントソフトなどを使用していると、text 形式表示も試せると思います。

定期的にメールを送ってみる

定期的にメールを送るには、

  1. タスクスケジューラに登録(windows)
  2. cron に登録(linax)
  3. コードの中で定期実行

する手段が考えられると思います。

今回は、コードの中で完結させたいので、3の方法をとってみます。
(ラズパイに乗せるときは、cron 登録で実行の予定)

loopmailsend.js として以下を保存します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
const Mailer = require("nodemailer");

//使用するSMTPサーバに関する設定
const Smtpsetting = {
//Webサービスを使う場合
service: "Gmail",
secure: true,
auth: {
user: "[Gmailアドレス]",
pass: "[Gmailアカウントのパスワード]",
port: "465", //使用ポートGmailは465だった
},
};

let GetMailObject = (() => {
//メールの内容
let Mailobject = {
from: "[送信元アドレス]",
to: "[送信先アドレス]",
subject: "This mail is test.",
text: "", //テキスト形式のメール本文
html: "", //html形式のメール本文
};

let count = 0;

return () => {
let date = new Date();
//取得時刻化から文字列を作成
let timestr =
" " +
(date.getMonth() + 1) +
"/" +
date.getDate() +
" " +
date.getHours() +
":" +
date.getMinutes() +
"[" +
date.getSeconds() +
"]";

count += 1;

Mailobject.text = `
${count}件目のテストのメールです。
現在時刻は${timestr}です
テストなので、返信不要です。
`;
Mailobject.html = `
<html>
<head>
</head>
<body>

<h1>${count}件目のテストのメールです</h1>
<p>現在時刻は${timestr}です。</p>
<p>テストなので、返信不要です。</p>
</body>
</html>
`;
return Mailobject;
};
})();

//SMTP接続の作成
let Smtp = Mailer.createTransport("SMTP", Smtpsetting);

//メール送信を関数定義
let Send = () =>
Smtp.sendMail(GetMailObject(), function (err, res) {
if (err) {
//送信に失敗したとき
console.log("送信失敗\n=>" + err);
} else {
//送信に成功したとき
console.log("送信成功\n=>" + res.message);
}
//SMTP接続の切断
Smtp.close();
});

//メール送信
for (let i = 0; i < 10; i++) {
Send();
}

node .\loopmailsend.jsで実行する。

これは失敗する
ループで 10 件送ったはずなのに、4 件だったり、10件だったり・・・。
さらにカウントアップしているはずなのに、全件の内容が同一になったりする。
理由は sendMail 関数が、非同期関数であるため。
もし順にカウントアップするなら、
それなりの方法が必要

ちゃんと定期的にメールを送ってみる[async await で修正]

loopmailsend-sync.js として以下を保存する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
const Mailer = require("nodemailer");

//使用するSMTPサーバに関する設定
const Smtpsetting = {
//Webサービスを使う場合
service: "Gmail",
secure: true,
auth: {
user: "[Gmailアドレス]",
pass: "[Gmailアカウントのパスワード]",
port: "465", //使用ポートGmailは465だった
},
};

let GetMailObject = (() => {
//メールの内容
let Mailobject = {
from: "[送信元アドレス]",
to: "[送信先アドレス]",
subject: "This mail is test.",
text: "", //テキスト形式のメール本文
html: "", //html形式のメール本文
};

let count = 0;

return () => {
let date = new Date();
//取得時刻から文字列を作成
let timestr =
" " +
(date.getMonth() + 1) +
"/" +
date.getDate() +
" " +
date.getHours() +
":" +
date.getMinutes() +
"[" +
date.getSeconds() +
"]";

count += 1;

Mailobject.text = `
${count}件目のテストのメールです。
現在時刻は${timestr}です
テストなので、返信不要です。
`;
Mailobject.html = `
<html>
<head>
</head>
<body>
<h1>${count}件目のテストのメールです</h1>
<p>現在時刻は${timestr}です。</p>
<p>テストなので、返信不要です。</p>
</body>
</html>
`;
return Mailobject;
};
})();

//SMTP接続の作成
let Smtp = Mailer.createTransport("SMTP", Smtpsetting);

//メール送信を関数定義
let Send = async () => {
return new Promise((resolve, reject) => {
Smtp.sendMail(GetMailObject(), function (err, res) {
if (err) {
//送信に失敗したとき
console.log("送信失敗\n=>" + err);
reject("送信失敗\n=>" + err);
} else {
//送信に成功したとき
console.log("送信成功\n=>" + res.message);
resolve("送信成功\n=>" + res.message);
}
});
});
};

//待ち時間用スリープ関数定義
let Sleep = async (time) => {
return new Promise((resolve) =>
setTimeout(() => {
console.log(`timeout${time}ms`);
resolve();
}, time)
);
};

//メール送信 非同期関数を即時実行
(async function SendLoop() {
console.log("送信開始");
for (let i = 0; i < 10; i++) {
await Sleep(3000);
console.log("SendStart");
await Send();
console.log("SendEnd");
}
//SMTP接続の切断
Smtp.close();
})();

node .\loopmailsend-sync.jsで実行する。

10 件のメールが内容もカウントアップされながら送信されて来たはずです。
このコードでは 3 秒間隔のタイムアウトを挟んで、10 件メールの送信をしてみました。
手元の環境ではメール送信処理自体が、1 秒程度かかっていたので実際には4~5秒程度の間隔のメール送信になります。

感想とか

今回は node.js でメール送信を(ライブラリもあるし)割合簡単に実装できました。
ラズパイと組み合わせれば、センサー値をメールで通知ができるようになります。
追加で通知手段として twitter も組み合わせたり、外部からコマンドを発行して通知を返すとかも作ってゆきたいですね。

連休に、距離センサー買ったりサーボモーター動かしてみたりしたので、
早く形にして、記事にまとめたいですね。

ではでは。