0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SymfonyAdvent Calendar 2019

Day 15

symfony/mailer でTwigを使ってテキストメールをbase64で送る。

Last updated at Posted at 2019-12-14

Symfony Advent Calendar 2019 15日目の記事です。

はじめに

メールを業務で利用する場合は、定型文を用意して、例えば、お客様の名前とか日付とかを、送信する相手毎に置換をしてから送信をすることが多いです。

メールの本文を、str_replaceで置換をしてもよいのですが、テンプレートエンジンのtwigを使ってみたくなります。

Twig: HTML & CSSを試す

Twigを使ってメールを送る方法について見ていきます。

Mailerドキュメントに、Twig: HTML & CSSの項目がありますので、そのまま実行してみます。

MailerController.php
class MailerController extends AbstractController
{
    /**
     * @Route("/mailer", name="mailer")
     */
    public function index(MailerInterface $mailer)
    {

        $email = (new TemplatedEmail())
            ->from('fabien@example.com')
            ->to(new Address('ryan@example.com'))
            ->subject('Thanks for signing up!')

            // path of the Twig template to render
            ->htmlTemplate('emails/signup.html.twig')

            // pass variables (name => value) to the template
            ->context([
                'expiration_date' => new \DateTime('+7 days'),
                'username' => 'foo',
            ])
        ;

        $mailer->send($email);

        return $this->render('mailer/index.html.twig', [
            'controller_name' => 'MailerController',
        ]);
    }
}

このソースは、https://github.com/idani/symfony_mailer_tutorial3 で保管しています。
今回のコミットは以下で見れます。
https://github.com/idani/symfony_mailer_tutorial3/commit/39d7caa797f0d1e663ba517553d8b23b8b319410

http://localhost:8000/mailer を開くと、以下の画面が表示されました。メール送信ができたようです。一番下のデバッグ用のツールバーのメールアイコンにも、メールが1通送信されたことが表示されていますね。

image.png

http://127.0.0.1:8025/ で動作しているMailDevを確認すると、1通メールが届いていました。
デフォルトで表示されるのは、TwigでレンダリングされたHTMLメールになります。

image.png

MailDevで設定を切り替えて、テキストメールにしてみます。
その場合は、HTMLからテキストを抽出したテキストメールが表示されます。

誤解されないように説明すると、MailDevはメールソースに記載されたテキストメールの部分を表示しています。テキストのメールは、symfony/mailerによって、配信前にHtmlからテキストを抽出して、メールソースに組み込まれています。

image.png

メールソースは以下です。

Content-Typetext/plain; charset=utf-8と指定されたテキストと、text/html; charset=utf-8と指定されたHTMLがquoted-printableでエンコードされて送られています。

メールソース
From: fabien@example.com
To: ryan@example.com
Subject: Thanks for signing up!
Message-ID: <a7169f3be53c5470e3765e9fc649f5b1@example.com>
MIME-Version: 1.0
Date: Thu, 05 Dec 2019 15:53:55 +0900
Content-Type: multipart/alternative;
 boundary="_=_symfony_1575528835_8df53d757797744c9475726f052de156_=_"

--_=_symfony_1575528835_8df53d757797744c9475726f052de156_=_
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Welcome !


    You signed up as foo the following email:

ryan@e=
xample.com


    Click here to activate your account
    (this link=
 is valid until December 12th)


--_=_symfony_1575528835_8df53d757797744c9475726f052de156_=_
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable

<h1>Welcome !</h1>

<p>
    You signed up as foo the following email:=

</p>
<p><code>ryan@example.com</code></p>

<p>
    <a href=3D"#"=
>Click here to activate your account</a>
    (this link is valid until De=
cember 12th)
</p>

--_=_symfony_1575528835_8df53d757797744c9475726f052de156_=_--

Text Contentを試す。

Mailerドキュメントを読み進めると、Text Contentの部分で、メールに入っているテキスト部分をカスタマイズできるようです。

さっそく、サンプルソースに->textTemplate('emails/signup.txt.twig')を追加します。

MailerController.php
        $email = (new TemplatedEmail())
            ->from('fabien@example.com')
            ->to(new Address('ryan@example.com'))
            ->subject('Thanks for signing up!')

            // path of the Twig template to render
            ->htmlTemplate('emails/signup.html.twig')

            // pass variables (name => value) to the template
            ->context([
                'expiration_date' => new \DateTime('+7 days'),
                'username' => 'foo',
            ])
            ->textTemplate('emails/signup.txt.twig')
        ;

        $mailer->send($email);
signup.txt.twig
Welcome !

    You signed up as foo the following email:

    {{ email.to[0].address }}


    Click here to activate your account

    http://www.example.com/xxxxxxxxxxx
    (this link is valid until {{ expiration_date|date('F jS') }})

実際に送信をされたメールを見ると、修正通りのテキストメールが送られていました。

image.png

メールソース
From: fabien@example.com
To: ryan@example.com
Subject: Thanks for signing up!
Message-ID: <f6cc0e2166ff05ab5816d2bb26255080@example.com>
MIME-Version: 1.0
Date: Thu, 05 Dec 2019 16:27:04 +0900
Content-Type: multipart/alternative;
 boundary="_=_symfony_1575530824_57df7e1ab6fbb47d7ffce4184ba1587c_=_"

--_=_symfony_1575530824_57df7e1ab6fbb47d7ffce4184ba1587c_=_
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Welcome !

    You signed up as foo the following email:

    ryan@=
example.com


    Click here to activate your account

    http:/=
/www.example.com/xxxxxxxxxxx
    (this link is valid until December 12th)
--_=_symfony_1575530824_57df7e1ab6fbb47d7ffce4184ba1587c_=_
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable

<h1>Welcome !</h1>

<p>
    You signed up as foo the following email:=

</p>
<p><code>ryan@example.com</code></p>

<p>
    <a href=3D"#"=
>Click here to activate your account</a>
    (this link is valid until De=
cember 12th)
</p>

--_=_symfony_1575530824_57df7e1ab6fbb47d7ffce4184ba1587c_=_--

テキストメールだけ送る

これまではHTMLメールが主役で、テキストメールがおまけ的な感じでした。
Twigを使って、テキストメールだけ送るにはどうしたらよいでしょうか?

さきほどのサンプルコードから、htmlTemplateを外してみましょう。


        $email = (new TemplatedEmail())
            ->from('fabien@example.com')
            ->to(new Address('ryan@example.com'))
            ->subject('Thanks for signing up!')

            // path of the Twig template to render
            //->htmlTemplate('emails/signup.html.twig') <=コメントアウト

            // pass variables (name => value) to the template
            ->context([
                'expiration_date' => new \DateTime('+7 days'),
                'username' => 'foo',
            ])
            ->textTemplate('emails/signup.txt.twig')
        ;

        $mailer->send($email);

MailDevでは、意図した通り、テキストメールが見れました。
画像では変化がないので、メールソースを見ていただくと、テキストメールになっていることがわかります。

image.png

メールソース
From: fabien@example.com
To: ryan@example.com
Subject: Thanks for signing up!
Message-ID: <3d16b774412841ddbdef19077a4e8fc2@example.com>
MIME-Version: 1.0
Date: Thu, 05 Dec 2019 16:33:07 +0900
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Welcome !

    You signed up as foo the following email:

    ryan@=
example.com


    Click here to activate your account

    http:/=
/www.example.com/xxxxxxxxxxx
    (this link is valid until December 12th)

日本語テンプレートで送信をしてみる

問題ないと思いますが、テンプレートを日本語にしてみます。

signup.txt.twig
Welcome !
ようこそ 

    You signed up as {{ username }} the following email:
    次のメールアドレスで{{ username }}としてサインアップしました

    {{ email.to[0].address }}


    Click here to activate your account
    アカウントを有効にするにはここをクリックしてください

    http://www.example.com/xxxxxxxxxxx
    (this link is valid until {{ expiration_date|date('F jS') }})
    このリンクは{{ expiration_date|date('F jS') }}まで有効です

送信すると、以下のように問題なく日本語も表示されました。

image.png

メールソース
From: fabien@example.com
To: ryan@example.com
Subject: Thanks for signing up!
Message-ID: <0072478296801e97a3472e1ce06a9f38@example.com>
MIME-Version: 1.0
Date: Thu, 05 Dec 2019 16:41:55 +0900
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Welcome !
=E3=82=88=E3=81=86=E3=81=93=E3=81=9D =EF=BC=81

    You sig=
ned up as foo the following email:
    =E6=AC=A1=E3=81=AE=E3=83=A1=
=E3=83=BC=E3=83=AB=E3=82=A2=E3=83=89=E3=83=AC=E3=82=B9=E3=81=A7foo=E3=81=
=A8=E3=81=97=E3=81=A6=E3=82=B5=E3=82=A4=E3=83=B3=E3=82=A2=E3=83=83=E3=83=
=97=E3=81=97=E3=81=BE=E3=81=97=E3=81=9F=E3=80=82

    ryan@example.com=



    Click here to activate your account
    =E3=82=A2=E3=82=
=AB=E3=82=A6=E3=83=B3=E3=83=88=E3=82=92=E6=9C=89=E5=8A=B9=E3=81=AB=E3=81=
=99=E3=82=8B=E3=81=AB=E3=81=AF=E3=81=93=E3=81=93=E3=82=92=E3=82=AF=E3=83=
=AA=E3=83=83=E3=82=AF=E3=81=97=E3=81=A6=E3=81=8F=E3=81=A0=E3=81=95=E3=81=
=84

    http://www.example.com/xxxxxxxxxxx
    (this link is valid u=
ntil December 12th)
    =EF=BC=88=E3=81=93=E3=81=AE=E3=83=AA=E3=83=B3=
=E3=82=AF=E3=81=AF=E3=80=81December 12th=E3=81=BE=E3=81=A7=E6=9C=89=
=E5=8A=B9=E3=81=A7=E3=81=99=E3=80=82

Base64で送信する

ここまでできても合格なのですが、可能であれば、quoted-printableではなく、base64で送信をしたいです。

どうしたらよいのでしょうか?

TemplatedEmail.phpを見てみると、Email.phpの派生クラスであることがわかります。

Email.phpの中身は、symfony/mailerでbase64やiso-2022-jpを試してみるで見ていきましたが、quoted-printable固定となってしまいます。

そうすると、Twigでテキストをレンダリングして、それをメール本文として指定するのが良さそうです。

Creating and Using TemplatesRendering a Template in Servicesに、サービス内でのレンダリング方法が記載されています。

こちらを参考にして、サンプルコードを変更します。
Base64のメールの作成方法は、symfony/mailerでbase64やiso-2022-jpを試してみるから流用しますので、ガラッと変わります。

MailerController.php

        mb_language("uni");
        mb_internal_encoding("UTF-8");

        $subject = mb_encode_mimeheader('Thanks for signing up! 登録してくれてありがとうございます!!');
        $subject = str_replace("\r\n", '', $subject);

        $headers = (new Headers())
            ->addMailboxListHeader('From', [new Address('hello@example.com', mb_encode_mimeheader('送信者名'))])
            ->addMailboxListHeader('To', [new Address('you@example.com', mb_encode_mimeheader('受信者名'))])
            ->addTextHeader('Subject', $subject)
        ;

        $body = $twig->render('emails/signup.txt.twig', [
            'expiration_date' => new \DateTime('+7 days'),
            'username' => 'foo',
            'email' => 'you@example.com',
        ]);
        $textContent = new TextPart($body, 'utf-8', 'plain', 'base64');
        $email = new Message($headers, $textContent);

        $mailer->send($email);

テンプレートの方も、メールアドレスなどの情報も、自動で設定されていたようです。
このためメールアドレスも個別に指定するように変更します。

signup.txt.twig
Welcome !
ようこそ 

    You signed up as {{ username }} the following email:
    次のメールアドレスで{{ username }}としてサインアップしました

    {{ email }}


    Click here to activate your account
    アカウントを有効にするにはここをクリックしてください

    http://www.example.com/xxxxxxxxxxx
    (this link is valid until {{ expiration_date|date('F jS') }})
    このリンクは{{ expiration_date|date('F jS') }}まで有効です

想定通り、Twigを使ってテキストメールをBase64で送信することができました。

image.png

メールソース
From: =?UTF-8?B?6YCB5L+h6ICF5ZCN?= <hello@example.com>
To: =?UTF-8?B?5Y+X5L+h6ICF5ZCN?= <you@example.com>
Subject: Thanks for signing up!
 =?UTF-8?B?55m76Yyy44GX44Gm44GP44KM44Gm44GC44KK44GM?=
 =?UTF-8?B?44Go44GG44GU44GW44GE44G+44GZ77yB77yB?=
Message-ID: <a98efb8654df5bc230c364e0d1e476f4@example.com>
MIME-Version: 1.0
Date: Thu, 05 Dec 2019 17:15:07 +0900
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: base64

V2VsY29tZSAhCuOCiOOBhuOBk+OBnSDvvIEKCiAgICBZb3Ugc2lnbmVkIHVwIGFzIGZvbyB0aGUg
Zm9sbG93aW5nIGVtYWlsOgogICAg5qyh44Gu44Oh44O844Or44Ki44OJ44Os44K544GnZm9v44Go
44GX44Gm44K144Kk44Oz44Ki44OD44OX44GX44G+44GX44Gf44CCCgogICAgeW91QGV4YW1wbGUu
Y29tCgoKICAgIENsaWNrIGhlcmUgdG8gYWN0aXZhdGUgeW91ciBhY2NvdW50CiAgICDjgqLjgqvj
gqbjg7Pjg4jjgpLmnInlirnjgavjgZnjgovjgavjga/jgZPjgZPjgpLjgq/jg6rjg4Pjgq/jgZfj
gabjgY/jgaDjgZXjgYQKCiAgICBodHRwOi8vd3d3LmV4YW1wbGUuY29tL3h4eHh4eHh4eHh4CiAg
ICAodGhpcyBsaW5rIGlzIHZhbGlkIHVudGlsIERlY2VtYmVyIDEydGgpCiAgICDvvIjjgZPjga7j
g6rjg7Pjgq/jga/jgIFEZWNlbWJlciAxMnRo44G+44Gn5pyJ5Yq544Gn44GZ44CCCg==

TwigのテンプレートをDBに保存する

メールの本文をテンプレートという形で保存をして、レンダリングすることもできました。

ところが、メールは本文以外にサブジェクトというデータも必要です。
サブジェクトはDBに保存し、メールの本文のテンプレートはファイルシステムというのは微妙ですよね。

TwigのテンプレートもDBに保存できるとよいですね。

調べてみると、Twigのドキュメントで、Using a Database to store Templatesがありました。

ただ、こちらは純粋にTwigのテンプレートの読み出し先をDBにするということみたいです。

サイトとしてHTMLを表示するためでしたらよいのですが、メールとしては使いづらいですね。

それよりは、その次に記載のTwigのテンプレートを変数として受け取って処理をするための、Loading a Template from a Stringが良さそうです。

サンプルでテンプレートを読み込む部分を書き換えます。

MailerController.php
   public function index(MailerInterface $mailer, Environment $twig)
    {

        mb_language("uni");
        mb_internal_encoding("UTF-8");

        $subject = mb_encode_mimeheader('Thanks for signing up! 登録してくれてありがとうございます!!');
        $subject = str_replace("\r\n", '', $subject);

        $headers = (new Headers())
            ->addMailboxListHeader('From', [new Address('hello@example.com', mb_encode_mimeheader('送信者名'))])
            ->addMailboxListHeader('To', [new Address('you@example.com', mb_encode_mimeheader('受信者名'))])
            ->addTextHeader('Subject', $subject)
        ;

        $twigEmailTemplate =<<<EOL
Welcome !
ようこそ !

    これはTwigテンプレートを変数から読み込んでレンダリングしたメールです。

    You signed up as {{ username }} the following email:
~~~中略~~~
    (このリンクは、{{ expiration_date|date('F jS') }}まで有効です。

EOL;

        $template = $twig->createTemplate($twigEmailTemplate);
        $body = $template->render([
            'expiration_date' => new \DateTime('+7 days'),
            'username' => 'foo',
            'email' => 'you@example.com',
        ]);
        $textContent = new TextPart($body, 'utf-8', 'plain', 'base64');
        $email = new Message($headers, $textContent);

        $mailer->send($email);

        return $this->render('mailer/index.html.twig', [
            'controller_name' => 'MailerController',
        ]);
    }

image.png

まとめ

Twigを使って簡単にメールが送れることがわかりました。
Base64にするには、面倒なので、良さそうな修正案を考える必要てプルリクした方がよいですね。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?