node.js ejs にてpartial HTMLがエスケープされて出力される場合の対処法

今回はrailsのpartial的な使い方をEJSを使って行う方法を紹介するとともに、
HTMLが正しくエスケープされなかった場合の対処法を紹介します。

■正しくエスケープされない場合の対処法

(エラーになった人向け)
<%=body %>ではエスケープされないので、<-%body %>を使います。

[javascript]
<%-body %>
<div style="padding-top:30px;padding-bottom:30px;">http://<%=host %>/</div>
[/javascript]

■テンプレートを利用してメールを送る方法

「node.jsでHTMLメールを送る」では、EJSを使ってHTMLを送る方法を紹介しています。

■partialを埋め込む方法

フッターをつけたlayout.ejsに、partialで「今日は特売日!」な文章を埋め込みます。

[javascript]

var fs = require("fs");
var ejs = require("ejs");

fs.readFile("simpleMail.ejs","utf8", function(err,data){

var locals = {"userName":"Yoshihiko Hoshino"};
var partialResult = ejs.render(data,{"locals":locals});
fs.readFile("layout.ejs","utf8",function(err,partialData){

var layoutLocal = {"body":partialResult,"host":"shisuh.com"};
var completePage = ejs.render(partialData,{"locals":layoutLocal});
console.log("complete page is "+completePage);

});

});
[/javascript]

layout EJSファイル(layout.ejs)

[javascript]
<%-body %>
<div style="padding-top:30px;padding-bottom:30px;">http://<%=host %>/</div>
[/javascript]

partial EJSファイル(simpleMail.ejs)

[javascript]
<%=userName %>さん、こんにちわ<br><br>
CSSで
<span style="font-size:20px;background-color:yellow;color:red;font-weight:bold;">
スーパーの特売!!
</span>も表現できます。
<br>
[/javascript]

■Good

上記のコマンドのコンソールにHTMLが出力されれば成功です。
[bash]
complete page is Yoshihiko Hoshinoさん、こんにちわ<br><br>

CSSで
<span style="font-size:20px;background-color:yellow;color:red;font-weight:bold;">
スーパーの特売!!
</span>も表現できます。
<br>

[/bash]

■Bad

layout.ejsの<%-body %>を<%=body %>にした場合の出力を紹介します。
フッターはエスケープされずに出力されていますが、partial部分がエスケープされてしまっています。

[bash]
complete page is Yoshihiko Hoshinoさん、こんにちわ&lt;br&gt;&lt;br&gt;

CSSで
&lt;span style=&quot;font-size:20px;background-color:yellow;color:red;font-weight:bold;&quot;&gt;
スーパーの特売!!
&lt;/span&gt;も表現できます。
&lt;br&gt;

[/bash]

node.js ejsにてHTMLメールを送る

前回の記事では、EJSの基本TIPSを書きました。
それをふまえて、HTMLメールを送るTIPSを紹介します。

■メールを送る方法

こちらのブログ様にインスパイアされ、僕もemailjsを使う事にしました。

■テンプレートを使ってHTMLメールを送る方法

[javascript]
var fs = require("fs");
var ejs = require("ejs");
var email = require(‘emailjs/email’);
var server = email.server.connect({

host:’localhost’,
ssl:false

});
var headers = {
from:"xxxxxx@shisuh.com"
,to:"xxxxxx@gmail.com"
,subject:"今日は特売日!を送ります"
}
var message = email.message.create(headers);

fs.readFile("simpleMail.ejs","utf8", function(err,data){

var locals = {"userName":"Yoshihiko Hoshino"};
var renderResult = ejs.render(data,{"locals":locals});
headers.text = renderResult;
message.attach({data:renderResult,alternative:true});
server.send(message,function(err,message){
if(err != null){
throw new Error(err);
}else{
console.log("sendOK");
}
});
});
[/javascript]

EJSファイル

[javascript]
<%=userName %>さん、こんにちわ<br><br>
CSSで
<span style="font-size:20px;background-color:yellow;color:red;font-weight:bold;">
スーパーの特売!!
</span>も表現できます。
<br>
[/javascript]

■動作確認方法

sudo tail -f /var/log/maillog を監視することで動作確認できます。

■結果

node.js ejsにて HTMLメールを送った結果

node.js ejsにて HTMLメールを送った結果の画像です

node.jsのejsを用いて、renderしたHTMLを変数として扱う with EJS(TemplateEngine)

node.jsのテンプレートエンジンであるEJSは、expressとの組み合わせでHTMLを画面に表示する用途で紹介されています。
本ブログではもう一つ踏み込んだ、ライブラリを直接扱う方法を紹介させて頂きます。

EJSでは結果を変数に格納できるため、HTMLメールの送信、ログの出力、renderしたHTMLのデバッグなども可能です。
もちろん、 HTMLを自分好みのレイアウトにすることもできます。

■解決策

今回はnode.jsで書いた一番簡単な関数を紹介します。
次回、HTMLメール、HTMLテンプレートと続きます。

[javascript]
var fs = require("fs");
var ejs = require("ejs");
fs.readFile("sendmail.ejs","utf8", function(err,data){

var locals = {userName:"Yoshihiko Hoshino"};
console.log(ejs.render(data,{"locals":locals}));

});

[/javascript]

EJSファイル

[javascript]

<%=userName %>さん
アトサクに登録して頂きありがとうございます。

<%=userName %>さんのアカウントを有効にするため、
下記のURLをクリックして認証作業を行ってください。
この作業はURLをクリックするだけで終わります。

[/javascript]

Error: parser error, 18 of 135 bytes parsed (node.js Objective-C)の対処方法

Error: parser error, 18 of 135 bytes parsed という、expressのエラーが出た場合の対処法です。(Postのみ)
原因は、BodyParserの仕様にクライアントがそっていない可能性があります。

■解決策

プロパティを追加する際には、form-data/nameの後のコロンやダブルクオーテーションのチェック、改行コードに\r\nを必ず使う。

[objc]
//リクエスト名の追加
[body appendData:[[NSString stringWithFormat:@”Content-Disposition: form-data; name=\”%@\” \r\n”,keyName] dataUsingEncoding:NSUTF8StringEncoding]];
[/objc]

■確認方法

node.js 側のexpressのBodyParserを外し、req.bodyを文字列に変換して確認することができます。

■Good

[objc]
//結果用のデータを作成する。
NSMutableData *body = [NSMutableData data];
NSString *boundary = @”—–123456—–“;
//boundaryの追加
[body appendData:[[NSString stringWithFormat:@”–%@\r\n”, boundary] dataUsingEncoding:NSUTF8StringEncoding]];
//リクエスト名の追加
[body appendData:[[NSString stringWithFormat:@”Content-Disposition: form-data; name=\”%@\” \r\n”,keyName] dataUsingEncoding:NSUTF8StringEncoding]];
//改行
[body appendData:[@”\r\n” dataUsingEncoding:NSUTF8StringEncoding]];
//データの追加
[body appendData:bodyData];
//改行
[body appendData:[@”\r\n” dataUsingEncoding:NSUTF8StringEncoding]];
//閉じる
[body appendData:[[NSString stringWithFormat:@”–%@–\r\n”, boudary] dataUsingEncoding:NSUTF8StringEncoding]];

[/objc]

■Bad

改行コードに\nを使ってしまう。

[objc]

//結果用のデータを作成する。
NSMutableData *body = [NSMutableData data];
NSString *boundary = @”—–123456—–“;
//boundaryの追加
[body appendData:[[NSString stringWithFormat:@”–%@\r\n”, boundary] dataUsingEncoding:NSUTF8StringEncoding]];
//リクエスト名の追加
[body appendData:[[NSString stringWithFormat:@”Content-Disposition: form-data; name=\”%@\” \n”,keyName] dataUsingEncoding:NSUTF8StringEncoding]];
//改行
[body appendData:[@”\n” dataUsingEncoding:NSUTF8StringEncoding]];
//データの追加
[body appendData:bodyData];
//改行
[body appendData:[@”\n” dataUsingEncoding:NSUTF8StringEncoding]];
//閉じる
[body appendData:[[NSString stringWithFormat:@”–%@–\r\n”, boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[/objc]

■bad2

nameにクオーテーションをつけない。

[objc]
//結果用のデータを作成する。
NSMutableData *body = [NSMutableData data];
NSString *boundary = @”—–123456—–“;
//boundaryの追加
[body appendData:[[NSString stringWithFormat:@”–%@\r\n”, boundary] dataUsingEncoding:NSUTF8StringEncoding]];
//リクエスト名の追加
[body appendData:[[NSString stringWithFormat:@”Content-Disposition: form-data; name=%@ \r\n”,keyName] dataUsingEncoding:NSUTF8StringEncoding]];
//改行
[body appendData:[@”\r\n” dataUsingEncoding:NSUTF8StringEncoding]];
//データの追加
[body appendData:bodyData];
//改行
[body appendData:[@”\r\n” dataUsingEncoding:NSUTF8StringEncoding]];
//閉じる
[body appendData:[[NSString stringWithFormat:@”–%@–\r\n”, boudary] dataUsingEncoding:NSUTF8StringEncoding]];
[/objc]

NSURL stringWithUrl relativeToUrl return nilの対処法

[NSURL stringWithUrl: relativeToUrl ] return nilの対処法を紹介します。
■解決策

相対パスにスペースが入っている場合、エスケープすると解決します。

[objc]
NSString *relativeString = [@”/logtopickeywords.cms?query=test matches” stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[/objc]

上記のコードのようにNSStringのstringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncodingを相対パスに追加して下さい。

■Good

[objc]
NSString *relativeString = [@”/logtopickeywords.cms?query=test matches” stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

NSLog(@”relativeString is %@”,relativeString);
NSString *originalPath = @”http://localhost/original/?original”;

NSURL *newUrl = [NSURL URLWithString:relativeString relativeToURL:[NSURL URLWithString:originalPath]];

NSLog(@”new URL is %@”,[newUrl absoluteString]);

STAssertTrue([[newUrl absoluteString] length] > 0,@”newUrl is %@”,[newUrl absoluteString]);
[/objc]

■Bad

[objc]
NSString *relativeString = @”/logtopickeywords.cms?query=test matches”;
NSString *originalPath = @”http://localhost/original/?original”;
NSURL *newUrl = [NSURLURLWithString:relativeString relativeToURL:[NSURLURLWithString:originalPath]];
STAssertTrue([[newUrl absoluteString] length] > 0,@”newUrl is %@”,[newUrl absoluteString]);
[/objc]