WPAutoResponderで送られるメールが文字化けしてるよ!って言われたので直した時のメモ
もうこんな対応する人も居ないと思うのですけど一応書いておきます。
きーた初投稿なので細かいミスはゆるしてくだちぃ
▼バージョン
WordPress 3.8.3
WP Autoresponder 5.3.7
概要
特定のメールソフトでメールを受信すると文字化けする。(Outlook2014)
いろいろ他の事例見てると文字コードがUTF-8だと、メールソフトが勝手に文字コード変換して化けることがあるよ!みたいな事が書いてあったのでメールのソース確認してみたらUTF-8になってた。
で、これをiso-2022-jpで送れるようにしたいけど、そもそもこのプラグインが開発停止していてアップデートで今後改善されるとかなさそうだから自分で直しちゃえというのが今回の概要です。
とりあえずコード読んでみた
とりあえず文字のエンコードを変更できればゴールなので思い当たる関数で検索かけてみました。
でも、プラグイン内のファイルを全て検索してみてもwp_mail()もないし、そもそもwp_mail()はWP Multibyte Patchが有効になってれば勝手に文字コード最適化してくれるし、実際その関数を使ってメール送信してるプラグインからのメールはちゃんと文字コードがiso-2022-jpになってた。
ということは別の何かで送信してるくさい。
WPAutoResponderのソースコードを追っていったらlibディレクトリにmail_functions.phpっていうファイルがあった。
中を覗いて444行目あたりにこんな関数を発見!
function email($to,$subject,$body)
{
$transport = getEmailTransport();
$message = Swift_message::newInstance($subject);
$message->setFrom(array(get_option("admin_email")=>get_option("blogname")));
$message->setBody($body);
if(!is_array($to) || (count($to)<2)) {
$message->setTo($to);
$message->send();
} else {
foreach($to as $address => $name) {
if(is_int($address)) {
$message->setTo($name);
} else {
$message->setTo(array($address => $name));
}
$message->send();
}
}
}
なるほどー SwiftMailerつかってるっぽい…?
じゃあこのSwiftMailerの処理に干渉できれば文字コードが変えられそう
対策
SwiftMailerの処理に干渉するということで調べてみるとこのプラグインに入ってるSwiftMailerバージョンが4.1.7
更に調べてみるとそもそもこのバージョンのSwiftMailerってUTF-8しか対応してない!?
でも4.2.0からはiso-2022-jpの文字コードに対応したという記事を発見したのでSwiftMailerのバージョンアップを検討… マイナーバージョンアップだけだしそんなに処理は変わってないだろうということでプラグイン内のlibの中身を4.2.0で上書き
送信テストしてみるとあっさり送信できました。
後は文字コードを変更するだけなんだけど、これにやたら手こずってしまいました。
とりあえず文字コードをiso-2022-jpにするための処理は下記サイトを参考にさせていただきました。
▼参考サイト
SwiftMailerでJIS(iso-2022-jp)のメールを送る件
Practical Symfony #15: Swift Mailerによる日本語メールの作成
ここを見る限り前処理として
\Swift::init(function () {
\Swift_DependencyContainer::getInstance()
->register('mime.qpheaderencoder')
->asAliasOf('mime.base64headerencoder');
\Swift_Preferences::getInstance()->setCharset('iso-2022-jp');
});
このコードを追加し、あとは送信処理の前に
$to_user_message = \Swift_Message::newInstance()
->setSubject("UTF-8の自由名文字列")
->setFrom([ 'from@mail.addr' => '送信者のお名前'])
->setTo([ 'to@mail.addr' ])
->setBody("本文もUTF-8で適当にいれればよいです")
->setCharset('iso-2022-jp')
->setEncoder(new \Swift_Mime_ContentEncoder_PlainContentEncoder('7bit'));
// 最後二行が追加、そこまではUTF-8と同じ
とすればいいとのこと。
\Swift::init()関数はSwift Mailerのオートローダーが最初に動作する(Swift_で始まるクラスへアクセスする)ときに実行されるコールバック関数を登録するものです。
これも考慮して前処理の部分は書かないといけないみたいです。
上記のことを踏まえてemail関数直前においてみたりいろいろやって、エラーで画面真っ白になったり、全然文字コードがiso-2022-jpにならなくて心が折れそうになりながら、最終的にプラグインディレクトリ直下のwpresponder.phpのclass直前に前処理を追記。
function _wpr_nag()
{
$address = get_option("wpr_address");
if (!$address && current_user_can("manage_newsletters"))
{
add_action("admin_notices","no_address_error");
}
add_action("admin_notices","_wpr_admin_notices_show");
}
\Swift::init(function () {
\Swift_DependencyContainer::getInstance()
->register('mime.qpheaderencoder')
->asAliasOf('mime.base64headerencoder');
\Swift_Preferences::getInstance()->setCharset('iso-2022-jp');
});
class WP_Autoresponder {
function __construct() {
冒頭にも出てきたプラグイン内libディレクトリ内のmail_functions.phpにあるemail関数を以下に書き換え。
function email($to,$subject,$body)
{
$transport = getEmailTransport();
$message = Swift_message::newInstance($subject);
$message->setFrom(array(get_option("admin_email")=>get_option("blogname")));
$message->setBody($body);
$message->setCharset('iso-2022-jp');
$message->setEncoder(new \Swift_Mime_ContentEncoder_PlainContentEncoder('7bit'));
if(!is_array($to) || (count($to)<2)) {
$message->setTo($to);
$message->send();
} else {
foreach($to as $address => $name) {
if(is_int($address)) {
$message->setTo($name);
} else {
$message->setTo(array($address => $name));
}
$message->send();
}
}
}
これで一応文字コードがiso-2022-jpになってました。
ただ、Content-Transfer-Encodingがなぜかquoted-printableのままになっているという…
[追記]
早速直ったので追記します。
結論から言うと追加するところがたりませんでした。
冒頭で出したemail関数と同ファイル内に下記の関数があるのでこちらにも処理追加。
function dispatchEmail($mail)
{
try {
$transport = getMailTransport();
$mailer = Swift_Mailer::newInstance($transport);
$message = Swift_Message::newInstance($mail['subject']);
$message->setFrom(array($mail['from']=>$mail['fromname']));
$message->setTo(array($mail['to']));
$message->setCharset('iso-2022-jp');
$message->setEncoder(new \Swift_Mime_ContentEncoder_PlainContentEncoder('7bit'));
if (!empty($mail['reply_to']) && validateEmail($mail['reply_to']))
{
$message->setReplyTo($mail['reply_to']);
}
$mail['textbody'] = stripslashes($mail['textbody']);
if ($mail['htmlenabled']==1 && !empty($mail['htmlbody']))
{
$mail['htmlbody'] = stripslashes($mail['htmlbody']);
if ($mail['attachimages'] == 1)
{
attachImagesToMessageAndSetBody($message,$mail['htmlbody']);
}
else
{
$message->setBody($mail['htmlbody'],'text/html');
}
$message->addPart($mail['textbody'],'text/plain');
}
else
{
$message->setBody($mail['textbody'],'text/plain');
}
$mailer->send($message);
_wpr_increment_hourly_email_sent_count();
}
catch (Exception $exp)
{
//do something here..
}
}
これで正常に表示されました。
まとめ
この記事みたいなことで悩んでいる人はほぼ居ないとは思いますが、一応出来たので共有させていただければと思います。
現状はこれで送信できていますが、また何か変更や不具合あったら追記していきたいと思います。