Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Djangoでのメール送信 - 設定からテストまで/djangocongress-jp-201...
Search
thinkAmi
May 18, 2019
Programming
1
12k
Djangoでのメール送信 - 設定からテストまで/djangocongress-jp-2019-talk
DjangoCongress JP 2019の発表資料です
thinkAmi
May 18, 2019
Tweet
Share
More Decks by thinkAmi
See All by thinkAmi
知ろう!使おう!HDF5ファイル!/pycon-jp-2019-talk
thinkami
4
9.5k
Django・WSGIミドルウェア入門/django-congress-jp-2018-talk
thinkami
4
4.9k
自分のための機械学習をしてみた話
thinkami
0
600
Xamarinで作るAndroid Wearアプリ
thinkami
1
2.6k
FluentMigratorでDBマイグレーション
thinkami
0
2.1k
デプロイボタンを使ってみた
thinkami
0
940
Vagrant + Berkshelf でお手軽写経環境構築
thinkami
1
1.3k
Twilio入門
thinkami
0
1.5k
おひとりさま環境でのChef-solo使用例
thinkami
2
1.4k
Other Decks in Programming
See All in Programming
Cancel Next.js Page Navigation: Full Throttle
ypresto
1
170
(Deep|Web) Link support with expo-router
mrtry
0
170
2024-10-02 dev2next - Application Observability like you've never heard before
jonatan_ivanov
0
170
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
8
520
Real-time message handling and notifications with API Platform and Symfony
alli83
1
100
Rails 8 Frontend: 10 commandments & 7 deadly sins in 2025
yshmarov
1
630
フロントエンドの現在地とこれから
koba04
10
4.5k
◯◯エンジニアになった理由
gessy0129
PRO
0
650
4年間変わらなかった YOUTRUSTのアーキテクチャ
daiki1003
1
540
自分だけの世界を創るクリエイティブコーディング / Creative Coding: Creating Your Own World
chobishiba
2
850
Micro Frontends for Java Microservices - dev2next 2024
mraible
PRO
0
200
個人開発で使ってるやつを紹介する回
yohfee
1
700
Featured
See All Featured
Infographics Made Easy
chrislema
239
18k
How to train your dragon (web standard)
notwaldorf
87
5.6k
Designing with Data
zakiwarfel
98
5.1k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
1
280
Music & Morning Musume
bryan
46
6.1k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
191
16k
Atom: Resistance is Futile
akmur
261
25k
The Art of Programming - Codeland 2020
erikaheidi
51
13k
GraphQLとの向き合い方2022年版
quramy
43
13k
Agile that works and the tools we love
rasmusluckow
327
21k
Fireside Chat
paigeccino
32
3k
4 Signs Your Business is Dying
shpigford
180
21k
Transcript
Django でのメール送信 ~ 設定からテストまで ~ DjangoCongress JP 2019 talk 2019/5/18
@thinkAmi
お前誰よ / Who are you ? @thinkAmi Python & Django
Blog :メモ的な思考的な (http://thinkami.hatenablog.com/) ( 株) 日本システム技研 PyCon JP 2016-18 Silver Sponsor ギークラボ長野 Python Boot Camp in 長野 みんなのPython 勉強会 in 長野
質問
Django でメール送信の経験がある方
簡単! Django でメール送信
設定ファイル # settings.py EMAIL_HOST = 'smtp.example.com' # 送信メールサーバ EMAIL_PORT =
'587' # 送信メールポート EMAIL_HOST_USER = 'test_user' # 送信ユーザ EMAIL_HOST_PASSWORD = 'Passw0rd' # 送信パスワード
send_mail() 関数の実行 send_mail(subject='my subject', # 件名 message='My Body', # 本文
from_email='
[email protected]
', # 送信者 recipient_list=['
[email protected]
']) # 受信者(To) のリスト
受信メール
メールの送信 send_mail(subject='my subject', # 件名 message='My Body', # 本文 from_email='
[email protected]
',
# 送信者 recipient_list=['
[email protected]
']) # 受信者(To) のリスト
話すこと Django のメール送信の流れ EmailMessage EmailBackend メール送信とunittest ショートカット関数 エラー通知メール エラー通知の仕組み 内容のマスク
話さないこと 仕組み以外の話 メールのRFC メール配信サービスの設定 SendGrid Amazon SES
注意 このトークを聴いても、Django アプリは作れません スライドは公開 スライド中のソースコードは、一部省略 GitHub に全体を公開済 https://github.com/thinkAmi/DjangoCongress_JP_2019_talk
環境 Python 3.7.3 Django 2.2.1 LTS
目次 Django のメール送信の流れ unittest ショートカット関数 エラー通知メール
Django のメールの仕組み send_mail() 関数を元に理解する
send_mail() 関数は何をしているか # django.core.mail.__init__.py def send_mail(subject, message, from_email, recipient_list, fail_silently=False,
auth_user=None, auth_password=None, connection=None, html_message=None): # EmailBackend オブジェクトを取得 connection = connection or get_connection() # EmailMessage 系オブジェクトを生成 mail = EmailMultiAlternatives( subject, message, from_email, recipient_list, connection=connection) # EmailMessage 系オブジェクトで送信 return mail.send()
send_mail() 関数 メール送信のショートカット関数 実際 EmailMessage EmailBackend
EmailMessage について
EmailMessage の役割 メール属性を持つ EmailBackend を使ってメールを送信
EmailMessage のメール属性 from_email, to, cc, bcc, reply_to subject body attachments
extra_headers connection EmailBackend
EmailMessage とsend_mail() の違い できること どちらでも EmailMessage のみ
どちらでもできる例 メールアドレスに表示名を付けたい HTML メールを送信したい メールテンプレートを使いたい
メールアドレスの表示名とは from_user <
[email protected]
>
メールアドレスに表示名を付ける # EmailMessage の場合 email = EmailMessage( from_email='from_user <
[email protected]
>', ...)
# send_mail() の場合 send_mail(from_email='from user <
[email protected]
>')
受信メール ( ヘッダ) From: from_user <
[email protected]
>
HTML メールを送信したい # EmailMessage( のサブクラス) の場合 email = EmailMultiAlternatives( body='My
Body', ...) email.attach_alternative('<strong>HTML メール</strong> です', 'text/html') email.send() # send_mail() の場合 send_mail(html_message='<strong>HTML メール</strong> です')
受信メール テキスト表示 HTML 表示
メールでテンプレートを使いたい render_to_string() 関数と組み合わせる
テンプレートエンジンを変更 TEMPLATES = [ { # View は、Django エンジン 'BACKEND':
'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], }, { # メールは、Jinja2 エンジン 'BACKEND': 'django.template.backends.jinja2.Jinja2', 'DIRS': [os.path.join(BASE_DIR, 'template_jinja2')], }, ]
テキストメールのテンプレート # base.txt メールのベースです {% block mail_content %} {% endblock
%} {% include './signature.txt' %} # content.txt {% extends './base.txt' %} {% block mail_content %} {{ message }} {% endblock %} # signature.txt from thinkAmi
テンプレートを利用して送信 template_body = render_to_string('mail/content.txt', context={'message': ' 埋め込みます'}) # EmailMessage の場合
email = EmailMessage(body=template_body, ...) # send_mail() の場合 send_mail(message=template_body, ...)
受信メール
EmailMessage のみできる例 添付ファイル
添付ファイル EmailMessage のメソッドを使用 関数 引数 添付ファイル名 __init__() MIMEBase 系, tuple
( *) 指定可 attach() 〃 〃 attach_file() ファイルシステム上のパス ファイルシステムと同一 * tuple(filename, content, mimetype)
メソッドの使い方 # 静的ディレクトリにあるファイルを添付する static_file_dir = pathlib.Path(settings.STATICFILES_DIRS[0]) image_file = static_file_dir.joinpath('images', 'shinanogold.png')
# __init__ の場合 with image_file.open(mode='rb') as f: EmailMessage(attachments=[('my.png', f.read(), 'image/png')], ...).send() # attach_file の場合 msg = EmailMessage(...) msg.attach_file(image_file) msg.send()
__init__ での結果
attach_file での結果
EmailBackend について
EmailBackend とは メールを送信する手段 拡張や自作も可能
EmailBackend の種類 Django 標準 django.core.mail.backends メール内容をどこに出力するかで使い分け SMTP コンソール ファイル インメモリ
ダミー
EmailBackend の指定 settings の EMAIL_BACKEND デフォルト SMTP
EmailBackend に必要な設定 EmailBackend により異なる # SMTP 時のsettings EMAIL_HOST = 'smtp.example.com'
# 送信メールサーバ EMAIL_PORT = '587' # 送信メールポート EMAIL_HOST_USER = 'test_user' # 送信ユーザ EMAIL_HOST_PASSWORD = 'Passw0rd' # 送信パスワード
EmailBackend の拡張 例 console.EmailBackend でも、件名を日本語で見たい Subject: =?utf-8?b?5Lu25ZCN44Gn44GZ?=
console.EmailBackend を拡張 write_message() メソッドをオーバーライド # myapp.email_backends.py class ReadableSubjectEmailBackend(console.EmailBackend): def write_message(self,
message): from email.header import decode_header subject = message.message().get('Subject') decoded_tuple = decode_header(subject) # => [('Django', None)] # MIME ヘッダエンコーディングなし # => [(b'\xe3\x82\xb8\xe3\x83\xa3\xe3\x83\xb3\xe3\x82\xb4', 'utf-8')] if decoded_tuple[0][1] is not None: readable_subject = decoded_tuple[0][0].decode( decoded_tuple[0][1]) self.stream.write(f'\nSubject ( 日本語表示): {readable_subject}\n') super().write_message(message)
settings EMAIL_BACKEND = 'myapp.email_backends.ReadableSubjectEmailBackend'
結果 Subject ( 日本語表示): ジャンゴ Content-Type: text/plain; charset="utf-8" Subject: =?utf-8?b?44K444Oj44Oz44K0?=
EmailBackend を自作 send_messages() メソッドを実装したクラスを用意 django.core.mail.backends.base.BaseEmailBackend を継承すると楽
例 メール送信ではなく、Slack に投稿したい SlackBackend
SlackBackend の実装 メールのBody をSlack へ投稿する from slackclient import SlackClient class
SlackBackend(BaseEmailBackend): def send_messages(self, email_messages): payload = email_messages[0].message().get_payload() client = SlackClient(settings.SLACK_OAUTH_ACCESS_TOKEN) client.api_call( 'chat.postMessage', channel=settings.SLACK_CHANNEL, text=payload, )
settings EMAIL_BACKEND = 'myapp.email_backends.SlackBackend' SLACK_OAUTH_ACCESS_TOKEN = 'Your OAuth Access Token'
SLACK_CHANNEL = 'Your Channel ID'
メールの送信処理 EmailMessage( subject='Django', body='DjangoCongress JP 2019 にようこそ!', from_email=settings.REAL_MAIL_FROM, to=settings.REAL_MAIL_TO).send()
結果
ここまでのまとめ EmailMessage でメール情報を作る EmailBackend を使って送信する
目次 Django のメール送信の流れ unittest ショートカット関数 エラー通知メール
開発時の悩み メール内容の確認をしたい 実メールサーバに送信したくない
実メールサーバ以外での確認 EmailBackend を差し替え コンソールやファイルなど Python のSMTP サーバ DebuggingServer を宛先にして送信
unittest 時 メールは送信されない EmailBackend が locmem.EmailBackend に差し替わる
差し替えているところ settings.TEST_RUNNER django.test.runner.DiscoverRunner setup_test_environment() django.test.utils.setup_test_environment() # https://github.com/django/django/blob/2.2.1/django/test/utils.py#L103 # EmailBackend の差し替え
settings.EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend' # メールボックスの初期化 mail.outbox = []
locmem に差し替わると django.core.mail.outbox に、EmailMessage のリストが設定
テスト対象の関数 def my_send_mail(encoding='utf-8', has_attachment=False): msg = EmailMessage( subject=' 件名', body='
本文', from_email=' 差出人 <
[email protected]
>', to=[' 送信先1 <
[email protected]
>', ' 送信先2 <
[email protected]
>'], cc=[' シーシー <
[email protected]
>'], bcc=[' ビーシーシー <
[email protected]
>'], reply_to=[' 返信先 <
[email protected]
>'], headers={'Sender': '
[email protected]
'}) if has_attachment: # 静的ディレクトリにあるファイルを添付する img = pathlib.Path(settings.STATICFILES_DIRS[0]).joinpath( 'images', 'shinanogold.png') msg.attach_file(img) msg.send()
mail.outbox の動作確認 class TestSendMail(TestCase): def _callFUT(self, encoding='utf-8', has_attachment=False): from myapp.utils
import my_send_mail my_send_mail(encoding=encoding, has_attachment=has_attachment) def test_send_multiple(self): # 実行前はメールボックスに何もない self.assertEqual(len(mail.outbox), 0) # 1 回実行すると、メールが1 通入る self._callFUT() self.assertEqual(len(mail.outbox), 1) # もう1 回実行すると、メールが2 通入る self._callFUT() self.assertEqual(len(mail.outbox), 2)
各フィールドの検証 def test_mail_fields(self): self._callFUT() actual = mail.outbox[0] self.assertEqual(actual.subject, ' 件名')
self.assertEqual(actual.body, ' 本文') self.assertEqual(actual.from_email, ' 差出人 <
[email protected]
>') # 宛先系はlist として設定される self.assertEqual(actual.to, [' 送信先1 <
[email protected]
>', ' 送信先2 <
[email protected]
>'],) # 追加ヘッダも含まれる self.assertEqual(actual.extra_headers['Sender'], '
[email protected]
')
添付ファイルがある場合 def test_attachment(self): self._callFUT(has_attachment=True) actual = mail.outbox[0] # 添付ファイル自体を検証 img
= pathlib.Path(settings.STATICFILES_DIRS[0]).joinpath( 'images', 'shinanogold.png') with img.open('rb') as f: expected_img = f.read() # tuple(filename, content, mimetype) self.assertEqual(actual.attachments[0][1], expected_img)
ここまでのまとめ unittest では、メールは送信されない django.core.mail.outbox に、EmailMessage のリストが設定
目次 Django のメール送信の流れ unittest ショートカット関数 エラー通知メール
ショートカット関数 User モデル email_user() 一括送信 send_mass_mail() 管理者宛送信 mail_admins() mail_managers()
User モデルの email_user() # ユーザー foo を取得 foo_user = User.objects.get(username='foo')
# ユーザー foo のメールアドレスへ送信 foo_user.email_user( subject='Hello', message='Welcome!', from_email='
[email protected]
', connection=console.EmailBackend(), )
send_mass_mail() 1 接続で複数のメールを送信 複数件送信する場合、 send_mail() より効率が良い msg1 = ('shortcut subject1',
'Shortcut Body', '
[email protected]
', ['
[email protected]
', '
[email protected]
']) msg2 = ('shortcut subject2', 'Shortcut Body', '
[email protected]
', ['
[email protected]
', '
[email protected]
']) send_mass_mail((msg1, msg2), connection=console.EmailBackend())
注意点 機能 EmailMessage send_mail() send_mass_mail() 宛先 To, Cc, Bcc, Reply-To
To To HTML メール 添付ファイル
管理者宛メールのショートカット関数 mail_admins() settings.ADMINS 宛にメール送信 mail_managers() settings.MANAGERS 宛にメール送信
ADMINS とMANAGERS の違い 公式ドキュメントより ADMINS = site admins MANAGERS =
site managers Django のエラー通知機能にて、両者の違いを見る
目次 Django のメール送信の流れ unittest ショートカット関数 エラー通知メール
Django のエラー通知メール Django アプリでエラーが発生した時に、メールで通知 サーバーエラー HTTP 500 リンク切れ Referer あり
& HTTP 404 存在しないページに直接アクセスした時は通知しない
サーバーエラー通知メールの仕組み # django.utils.log.py DEFAULT_LOGGING = { 'filters': { 'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'}, 'handlers': { 'mail_admins': { 'level': 'ERROR', 'filters': ['require_debug_false'], 'class': 'django.utils.log.AdminEmailHandler'}}, 'loggers': { 'django': { 'handlers': ['console', 'mail_admins']}}
設定の変更例 エラー通知メールは常にコンソール出力 LOGGING = { 'handlers': { 'mail_admins': { ...
'email_backend': # 追加 'django.core.mail.backends.console.EmailBackend'}
自作 AdminEmailHandler を継承し、 send_mail() をオーバーライド
例 エラーレポートのHTML をパスワード付zip ファイルにして送信 class MyAdminEmailHandler(AdminEmailHandler): def send_mail(self, subject, message,
*args, **kwargs): with TemporaryDirectory() as temp_dir: html_file = pathlib.Path(temp_dir).joinpath('report.html') with html_file.open('w') as f: f.write(kwargs.get('html_message')) # パスワード付zip ファイルを添付・送信 zip_file = pathlib.Path(temp_dir).joinpath('dst.zip') pyminizip.compress(str(html_file), None, str(zip_file), 'pass', 0) msg = EmailMessage(...) msg.attach_file(zip_file) msg.send()
結果
リンク切れ通知メールの仕組み django.middleware.common.BrokenLinkEmailsMiddleware
通知先の違い サーバーエラー MAIL_ADMINS リンク切れ MAIL_MANAGERS
サーバーエラーの通知設定 # 本番運用モードにする DEBUG = False # 送信先の site admins
のメールアドレスを設定 # (' メールアドレスコメント', ' メールアドレス') ADMINS = [('Admin1', '
[email protected]
')] # 他、使用するEmailBackend の設定を行う
サーバーエラー通知設定 ( 任意) # 送信元のメールアドレス # デフォルト:root@localhost SERVER_EMAIL = '
[email protected]
'
# エラー通知メールの件名のPrefix # デフォルト:[Django] EMAIL_SUBJECT_PREFIX = '[Hello]'
動作確認 $ curl http://localhost:8000/force_500 <h1>Server Error (500)</h1>
受信メール エラー内容やsettings 、POST データなどが含まれる デフォルトでは、ローカル変数は含まれない Subject: [Hello]ERROR (EXTERNAL IP): Internal
Server Error: /force_500 From:
[email protected]
To:
[email protected]
Internal Server Error: /force_500 ... Request Method: GET Request URL: http://localhost:8000/force_500 ... YEAR_MONTH_FORMAT =3D 'F Y'
ローカル変数もほしい時 単純な方法:Debug=True の時のHTML を含める # settings DEFAULT_LOGGING['handlers']['mail_admins']['include_html'] = True
動作確認 例外を発生するView def force_500(request): my_local_value = ' ハロー' raise Exception('Error')
ローカル変数を含むサーバーエラー通知メール Subject: [Hello]ERROR (EXTERNAL IP): Internal Server Error: /force_500 From:
[email protected]
To:
[email protected]
... <!DOCTYPE html> <tr> <td>my_local_value</td> <td class="code"><pre>' ハロー'</pre></td> </tr>
サーバーエラー通知メールの注意点 サーバー情報が漏洩する可能性あり settings ローカル変数 POST データ 必要に応じて、内容をマスクする
settings に対する、自動マスク機能 以下のパターンを含む設定名は、Django が自動でマスク API KEY PASS SECRET SIGNATURE TOKEN
動作確認 settings DJANGO_CONGRESS_PASSPORT = '123' DJANGO_CONGRESS_PASSWORD = '456' DJANGO_CONGRESS_PASTA =
'789'
結果 DJANGO_CONGRESS_PASSPORT =3D '********************' DJANGO_CONGRESS_PASSWORD =3D '********************' DJANGO_CONGRESS_PASTA =3D '789'
ローカル変数に対するマスク 以下の場合、デフォルトではそのまま表示 DEFAULT_LOGGING['handlers']['mail_admins']['include_html'] = True @sensitive_variables デコレータを使う
一部をマスクする例 View @method_decorator(sensitive_variables('region', 'year'), name='dispatch') class MaskedLocalVariableView(TemplateView): """ 一部ローカル変数をマスク """
template_name = 'myapp/breaking.html' def get(self, request, *args, **kwargs): conference = 'DjangoCongress' region = 'JP' # マスクする year = '2019' # マスクする raise Exception
一部マスクの結果 <li class="frame user"> <h2>Local Vars</h2> <td>conference</td> <td class="code"><pre>'DjangoCongress'</pre></td> <td>region</td>
<td class="code"><pre>'********************'</pre></td> <td>year</td> <td class="code"><pre>'********************'</pre></td>
すべてをマスクする例 View @method_decorator(sensitive_variables(), name='dispatch') class AllMaskedLocalVariableView(TemplateView): ...
エラー通知に含まれるPOST データ デフォルトでは、そのまま表示 Exception Type: Exception at /post_parameters POST: apple
=3D 'Shinano Gold' grape =3D 'Shine Muscat' pear =3D 'Southern Suite' @sensitive_post_parameters デコレータを使う
一部をマスクする例 View @method_decorator(sensitive_post_parameters('grape', 'pear'), name='dispatch') class MaskedPostParameterView(FormView): def post(self, request,
*args, **kwargs): raise Exception
一部マスクの結果 Request information: POST: apple =3D 'Shinano Gold' grape =3D
'********************' pear =3D '********************'
すべてをマスクする例 View @method_decorator(sensitive_post_parameters(), name='dispatch') class AllMaskedPostParameterView(FormView): ...
ちなみに ローカル変数とPOST データを両方マスク @method_decorator(sensitive_variables('year'), name='dispatch') @method_decorator(sensitive_post_parameters('grape'), name='dispatch') class DoubleMaskedView(FormView): ...
マスク機能を自作 デコレータをView に付けたくない 一括でマスクしたい 自作のマスク機能を作成することで対応可能 SafeExceptionReporterFilter のサブクラスが推奨
マスク機能 class MyReporterFilter(SafeExceptionReporterFilter): def get_post_parameters(self, request): """ POST データをマスク """
cleansed = request.POST.copy() cleansed['grape'] = '?' * 30 return cleansed def get_traceback_frame_variables(self, request, tb_frame): """ トレースバック中のローカル変数をマスク """ cleansed = {} for name, value in tb_frame.f_locals.items(): if name == 'year': value = '?' * 30 else: value = self.cleanse_special_types(request, value) cleansed[name] = value return cleansed.items()
自作マスク機能を使用 settings DEFAULT_EXCEPTION_REPORTER_FILTER = 'myapp.reporter_filter.MyReporterFilter'
マスク結果 Request information: POST: apple =3D 'Shinano Gold' grape =3D
'??????????????????????????????' pear =3D 'Southern Suite' ... <li class="frame user"> <h2>Local Vars</h2> <td>conference</td> <td class="code"><pre>'DjangoCongress'</pre></td> <td>region</td> <td class="code"><pre>'JP'</pre></td> <td>year</td> <td class="code"><pre>'??????????????????????????????'</pre></td>
リンク切れの通知設定 # 本番運用モードにする DEBUG = False # リンク切れを通知するミドルウェアを追加 MIDDLEWARE +=
['django.middleware.common.BrokenLinkEmailsMiddleware'] # 送信先の site managers のメールアドレスを設定 # (' メールアドレスコメント', ' メールアドレス') MANAGERS = [('Manager1', '
[email protected]
')] # 他、使用するEmailBackend の設定を行う
リンク切れの通知設定 ( 任意) # ADMINS と共用 SERVER_EMAIL = '...' EMAIL_SUBJECT_PREFIX
= '...' # HTTP404 でもエラーレポートメールを送信したくないURL がある場合は、正規表現で指定 IGNORABLE_404_URLS = [ re.compile(r'^/ignore_404$'), ]
動作確認 Referer ありで、HTTP 404 # 実際は1 行 $ curl -H
"Referer:http://localhost:8000/breaking_link" http://localhost:8000/force_404 <h1>Not Found</h1><p>The requested resource was not found on this server.</p>
受信メール Subject: [Hello]Broken INTERNAL link on localhost:8000 From:
[email protected]
To:
[email protected]
Referrer: http://localhost:8000/breaking_link Requested URL: /force_404 User agent: curl/7.54.0 IP address: 127.0.0.1
まとめ メール送信まわりは標準搭載 unittest ショートカット関数 エラー通知 メール送信まわりの機能は、いずれも拡張・自作可 エラー通知メールは、情報漏えいに注意 必要に応じてマスク
Enjoy Django email life!!
Appendix
エンコーディングの変更 メールのエンコーディング 非ASCII 文字を送信するために使用 ヘッダ 件名 Content-Type
デフォルトの挙動 件名に日本語をセット email = EmailMessage(subject=' 件名です', ...) 受信メール Content-Type: text/plain;
charset="utf-8" Content-Transfer-Encoding: 7bit Subject: =?utf-8?b?5Lu25ZCN44Gn44GZ?=
メールのエンコーディング設定 settings.DEFAULT_CHARSET utf-8 HttpResponse オブジェクトのエンコーディング
EmailMessage オブジェクトの属性 encoding メールのエンコーディングを変更可能
例 エンコーディングを ISO-2022-JP に変更 email = EmailMessage(subject=' 件名です', ...) email.encoding
= 'iso-2022-jp'
結果 受信メール Content-Type: text/plain; charset="iso-2022-jp" Content-Transfer-Encoding: 7bit Subject: =?iso-2022-jp?b?GyRCN29MPiRHJDkbKEI=?=
Thanks!!