node.jsでメール送信

node.jsがサーバーサイドのjsならメールも送れるんじゃね。
ということで調べてみました。

環境

メールサーバー:postfixのSMTP AUTH

nodeのフレームワークのexpressで環境を作る

$ npm install express
npm http GET https://registry.npmjs.org/express
npm http 304 https://registry.npmjs.org/express
npm http GET https://registry.npmjs.org/mkdirp/0.3.0
npm http GET https://registry.npmjs.org/qs
npm http GET https://registry.npmjs.org/mime/1.2.4
npm http GET https://registry.npmjs.org/connect
npm http 304 https://registry.npmjs.org/qs
npm http 304 https://registry.npmjs.org/mkdirp/0.3.0
npm http 200 https://registry.npmjs.org/mime/1.2.4
npm http GET https://registry.npmjs.org/mime/-/mime-1.2.4.tgz
npm http 304 https://registry.npmjs.org/connect
npm http 200 https://registry.npmjs.org/mime/-/mime-1.2.4.tgz
npm http GET https://registry.npmjs.org/formidable
npm http 200 https://registry.npmjs.org/formidable
npm http GET https://registry.npmjs.org/formidable/-/formidable-1.0.9.tgz
npm http 200 https://registry.npmjs.org/formidable/-/formidable-1.0.9.tgz
express@2.5.8 ./node_modules/express
tqq qs@0.4.2
tqq mime@1.2.4
tqq mkdirp@0.3.0
mqq connect@1.8.5

テンプレートエンジンはejsにしてmail_testディレクトリに雛形を作る

$ express -s -t ejs mail_test
   create : mail_test
   create : mail_test/package.json
   create : mail_test/app.js
   create : mail_test/public
   create : mail_test/public/javascripts
   create : mail_test/public/images
   create : mail_test/public/stylesheets
   create : mail_test/public/stylesheets/style.css
   create : mail_test/routes
   create : mail_test/routes/index.js
   create : mail_test/views
   create : mail_test/views/layout.ejs
   create : mail_test/views/index.ejs
   dont forget to install dependencies:

node.jsのmailパッケージをインストール

$ npm install mail
npm http GET https://registry.npmjs.org/mail
npm http 200 https://registry.npmjs.org/mail
npm http GET https://registry.npmjs.org/mail/-/mail-0.2.3.tgz
npm http 200 https://registry.npmjs.org/mail/-/mail-0.2.3.tgz
npm http GET https://registry.npmjs.org/reparse
npm http 200 https://registry.npmjs.org/reparse
npm http GET https://registry.npmjs.org/reparse/-/reparse-0.1.2.tgz
npm http 200 https://registry.npmjs.org/reparse/-/reparse-0.1.2.tgz
mail@0.2.3 ./node_modules/mail
mqq reparse@0.1.2

インストールできたのでapp.jsを編集する

app.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
var express = require('express')
  , routes = require('./routes');
 
var mail = require('mail').Mail({
  host: 'example.com',
  username: 'info@example.com',
  password: '**pass**'
});
 
mail.message({
  from: 'sender@example.net',
  to: ['info@example.com'],
  subject: 'Hello from Node.JS'
})
.body('Node speaks SMTP!')
.send(function(err) {
  if (err) throw err;
  console.log('Sent!');
});
 
var app = module.exports = express.createServer();
 
// Configuration
 
app.configure(function(){
  app.set('views', __dirname + '/views');
  app.set('view engine', 'ejs');
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(express.cookieParser());
  app.use(express.session({ secret: 'your secret here' }));
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});
 
app.configure('development', function(){
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
 
app.configure('production', function(){
  app.use(express.errorHandler());
});
 
// Routes
 
app.get('/', routes.index);
 
app.listen(3001);
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);

実行してみる

$ node app.js
 
node.js:201
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
ReferenceError: self is not defined
    at Client.smtpAUTH (/home/f1gp/models/node/mail_test/node_modules/mail/lib/smtp.js:252:5)
    at Array.extend (/home/f1gp/models/node/mail_test/node_modules/mail/lib/smtp.js:195:21)
    at Array.each [as 0] (/home/f1gp/models/node/mail_test/node_modules/mail/lib/util.js:158:10)
    at EventEmitter._tickCallback (node.js:192:40)

エラー:ReferenceError: self is not defined

lib/smtp.js:252行目の5文字目を見ると、selfをthisに変更したら動きそうだった。

lib/smtp.js

245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
Client.prototype.smtpAUTH = function(next, mechanisms) {
  var names = mechanisms.toUpperCase().split(/\s+/),
      method;
 
  if (!this.username)
    next();
  else if (!this.secure && !this.options.insecureAuth)
    // self → thisに勝手に修正してみる
    // self.emit('error', new Error('AUTH: stream is not secure (use `insecureAuth: true` to override).'));
    this.emit('error', new Error('AUTH: stream is not secure (use `insecureAuth: true` to override).'));
  else
    for (var i = 0, l = names.length; i < l; i++) {
      method = this['auth' + names[i]];
      if (method) {
        method.call(this, this.username, this.password, next);
        break;
      }
    }
};

もっかい実行する

$ node app.js
 
node.js:201
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
Error: AUTH: stream is not secure (use `insecureAuth: true` to override).
    at Client.smtpAUTH (/home/f1gp/models/node/mail_test/node_modules/mail/lib/smtp.js:252:24)
    at Array.extend (/home/f1gp/models/node/mail_test/node_modules/mail/lib/smtp.js:195:21)
    at Array.each [as 0] (/home/f1gp/models/node/mail_test/node_modules/mail/lib/util.js:158:10)
    at EventEmitter._tickCallback (node.js:192:40)

エラー:Error: AUTH: stream is not secure (use `insecureAuth: true` to override)

use `insecureAuth: true` to overrideってことで`insecureAuth: true`を追加してみる。

app.js

4
5
6
7
8
9
var mail = require('mail').Mail({
  host: 'example.com',
  username: 'info@example.com',
  password: '**pass**',
  insecureAuth: true //←追加した
});

もっかい実行する

$ node app.js
Express server listening on port 3001 in development mode
Sent!

送信できた!!

参考

weaver / node-mail

node.js覚書

node.jsのsocketのデバッグメッセージを表示しないオプション

サーバー側
var express = require('express');
var app = module.exports = express.createServer();
app.listen(3000);
var socketIO = require('socket.io');
var io = socketIO.listen(app);
 
// デフォルトがtrueなのでfalseにする
io.settings.log = false;

さくらのVPSにgitをyumでインストール

gitをインストールする時 yum を使ってインストールします。

$ sudo yum install git
Loaded plugins: downloadonly, fastestmirror
Loading mirror speeds from cached hostfile
* base: ftp.nara.wide.ad.jp
* extras: ftp.nara.wide.ad.jp
* updates: ftp.nara.wide.ad.jp
Excluding Packages in global exclude list
Finished
Setting up Install Process
Nothing to do

無いすか・・・。

gitはデフォルトのレポジトリには無いからrpmforgeのレポジトリを使うといいよ!
って教えてもらいました。

yumにrpmforgeのレポジトリが無い時は追加

# wget http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el6.rf.x86_64.rpm
# rpm -Uvh rpmforge-release-0.5.2-2.el6.rf.x86_64.rpm

普段は使いたくないので、利用されないように変更。

# vi /etc/yum.repos.d/rpmforge.repo
[rpmforge]
name = Red Hat Enterprise $releasever - RPMforge.net - dag
#baseurl = http://apt.sw.be/redhat/el6/en/$basearch/dag
mirrorlist = http://apt.sw.be/redhat/el6/en/mirrors-rpmforge
#mirrorlist = file:///etc/yum.repos.d/mirrors-rpmforge
enabled = 0 // 1を0へ変更
protect = 0
gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rpmforge-dag
gpgcheck = 1

できたら追加したrpmforgeレポジトリでインストールしてみる。

$ sudo yum install git --enablerepo=rpmforge

参考
[Linux]CentOSにyumでgitを導入
ウェブ開発者のための、1時間でできるLAMP環境構築術(CentOS編)

apcをyumでインストールした時のエラー

・PHP version 5.3.3
でAPCをyumでインストールした時後に、PHPを実行した時のエラーが

PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib64/php/modules/apc.so' 
- /usr/lib64/php/modules/apc.so: undefined symbol: php_pcre_exec in Unknown on line 0

だったのでメモ。

apcをyumでインストールしたけどphpをコマンドから実行した時にエラーがでるようになった。
phpinfo()で確認してもAPCが無い!
php.iniにextension=apc.soが無いからかーと思って、php.iniに追記して再起動してphpを実行すると

PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib64/php/modules/apc.so' 
- /usr/lib64/php/modules/apc.so: undefined symbol: php_pcre_exec in Unknown on line 0
PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib64/php/modules/apc.so' 
- /usr/lib64/php/modules/apc.so: undefined symbol: php_pcre_exec in Unknown on line 0

2個に増えました!!!!!!!

別のインストール方法ならどうかなーということで、

# yum remove *apc*

で削除。

peclでインストールしてみる

# pecl install apc 
downloading APC-3.1.9.tgz ...
Starting to download APC-3.1.9.tgz (155,540 bytes)
.........................done: 155,540 bytes
54 source files, building
running: phpize
Configuring for:
PHP Api Version:         20090626
Zend Module Api No:      20090626
Zend Extension Api No:   220090626
Enable internal debugging in APC [no] :(enter押す)
Enable per request file info about files used from the APC cache [no] :(enter押す)
Enable spin locks (EXPERIMENTAL) [no] :(enter押す)
Enable memory protection (EXPERIMENTAL) [no] :(enter押す)
Enable pthread mutexes (default) [yes] :(enter押す)
Enable pthread read/write locks (EXPERIMENTAL) [no] :(enter押す)
 
・
・
(略)
・
・
 
Build process completed successfully
Installing '/usr/include/php/ext/apc/apc_serializer.h'
Installing '/usr/lib64/php/modules/apc.so'
install ok: channel://pecl.php.net/APC-3.1.9
configuration option "php_ini" is not set to php.ini location
You should add "extension=apc.so" to php.ini

入った!

phpinfo()でも確認できました。
(php.iniにextension=apc.so書いてない人は追記して下さい)

2013年1月21日追記
後日やってみると下記のエラーでインストールできなかった。

running: make
/bin/sh /tmp/pear/temp/pear-build-rootj4HLaQ/APC-3.1.9/libtool --mode=compile gcc  -I. -I/tmp/pear/temp/APC -DPHP_ATOM_INC -I/tmp/pear/temp/pear-build-rootj4HLaQ/APC-3.1.9/include -I/tmp/pear/temp/pear-build-rootj4HLaQ/APC-3.1.9/main -I/tmp/pear/temp/APC -I/usr/include/php -I/usr/include/php/main -I/usr/include/php/TSRM -I/usr/include/php/Zend -I/usr/include/php/ext  -DHAVE_CONFIG_H  -g -O2   -c /tmp/pear/temp/APC/apc.c -o apc.lo
mkdir .libs
 gcc -I. -I/tmp/pear/temp/APC -DPHP_ATOM_INC -I/tmp/pear/temp/pear-build-rootj4HLaQ/APC-3.1.9/include -I/tmp/pear/temp/pear-build-rootj4HLaQ/APC-3.1.9/main -I/tmp/pear/temp/APC -I/usr/include/php -I/usr/include/php/main -I/usr/include/php/TSRM -I/usr/include/php/Zend -I/usr/include/php/ext -DHAVE_CONFIG_H -g -O2 -c /tmp/pear/temp/APC/apc.c  -fPIC -DPIC -o .libs/apc.o
/tmp/pear/temp/APC/apc.c:42:33: error: apc_php_pcre.h: No such file or directory
/tmp/pear/temp/APC/apc.c:393: error: expected specifier-qualifier-list before 'pcre'
/tmp/pear/temp/APC/apc.c: In function 'apc_regex_compile_array':
/tmp/pear/temp/APC/apc.c:454: error: 'apc_regex' has no member named 'preg'
/tmp/pear/temp/APC/apc.c:454: error: 'apc_regex' has no member named 'preg'
/tmp/pear/temp/APC/apc.c:455: error: 'apc_regex' has no member named 'nreg'
/tmp/pear/temp/APC/apc.c:455: error: 'apc_regex' has no member named 'nreg'
/tmp/pear/temp/APC/apc.c: In function 'apc_regex_match_array':
/tmp/pear/temp/APC/apc.c:487: error: 'apc_regex' has no member named 'preg'
/tmp/pear/temp/APC/apc.c:487: error: 'apc_regex' has no member named 'preg'
/tmp/pear/temp/APC/apc.c:488: error: 'apc_regex' has no member named 'nreg'
/tmp/pear/temp/APC/apc.c:488: error: 'apc_regex' has no member named 'nreg'
make: *** [apc.lo] Error 1
ERROR: `make' failed

yumのupdateをしたりしてやるも解決できず。

postfixadminでメールボックスが作成されない件

Postfix Admin 2.3.5でメルアド追加してもメールボックスが作成されなかったのでメモ。

postfixadminでドメインとアドレスを追加した時にメールボックスが作成されませんでした。
さくらVPSのお試し期間のOB25Pが原因かなーと思って
課金してみて再度やっても作成されません><。

postfixadminではメルアドを追加した時にそのメルアドにメールを送ってメールボックスを作成しているらしいです。該当部分はここ。

postfixadmin/function.inc.php

//
// smtp_mail
// Action: Sends email to new account.
// Call: smtp_mail (string To, string From, string Data)
// TODO: Replace this with something decent like PEAR::Mail or Zend_Mail.
function smtp_mail ($to, $from, $data)
{
    global $CONF;
    $smtpd_server = $CONF['smtp_server'];
    $smtpd_port = $CONF['smtp_port'];
    $smtp_server = $_SERVER["SERVER_NAME"];
    $errno = "0";
    $errstr = "0";
    $timeout = "30";
 
    $fh = @fsockopen ($smtpd_server, $smtpd_port, $errno, $errstr, $timeout);
 
    if (!$fh)
    {
        return false;
    }
    else
    {
        $res = smtp_get_response($fh);
        fputs ($fh, "EHLO $smtp_server\r\n");
        $res = smtp_get_response($fh);
        fputs ($fh, "MAIL FROM:<$from>\r\n");
        $res = smtp_get_response($fh);
        fputs ($fh, "RCPT TO:<$to>\r\n");
        $res = smtp_get_response($fh);
        fputs ($fh, "DATA\r\n");
        $res = smtp_get_response($fh);
        fputs ($fh, "$data\r\n.\r\n");
        $res = smtp_get_response($fh);
        fputs ($fh, "QUIT\r\n");
        $res = smtp_get_response($fh);
        fclose ($fh);
    }
    return true;
}
 
//
// smtp_get_response
// Action: Get response from mail server
// Call: smtp_get_response (string FileHandle)
//
function smtp_get_response ($fh)
{
    $res ='';
    do
{
    $line = fgets($fh, 256);
    $res .= $line;
}
while (preg_match("/^\d\d\d\-/", $line));
return $res;
}

メルアド追加時のメールログをみてみました。

/var/log/mail.log

warning: table "mysql:/etc/postfix/mysql_virtual_domains_maps.cf": empty lookup result for:****.com

どうやらmysql_virtual_domains_maps.cfが怪しいみたいです。

/etc/postfix/mysql_virtual_domains_maps.cf

user = postfix
password = *******
hosts = localhost
dbname = postfix
table = domain
select_field = description
where_field = domain

DB名postfixのdomain.descriptionをSELECTしているらしいので、該当カラムをみてみると空白でした。
おかしーなーと思って別のpostfixが稼働してるサーバーの該当カラムを見てみると
「No Description」という文字列が入っているではありませんか。

つまり、postfixadminでドメインを追加する時に、説明を空白のままドメインを追加すると
メルアドを追加してもメールボックスが作成されないということでした。

postfixadminでドメインを追加する時は説明を入力するようにしよう!!