From 80753e9538f2e3173113790996766e71e043ee20 Mon Sep 17 00:00:00 2001 From: Floodpants Date: Sat, 24 Jul 2021 18:31:36 +1000 Subject: [PATCH 1/3] make template.render() more flexible and move away from wrapping all supplied vars in 'body' --- fastapi_mail/fastmail.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/fastapi_mail/fastmail.py b/fastapi_mail/fastmail.py index 0ed8d59..071b3ac 100755 --- a/fastapi_mail/fastmail.py +++ b/fastapi_mail/fastmail.py @@ -55,14 +55,27 @@ def __init__(self, async def get_mail_template(self, env_path, template_name): return env_path.get_template(template_name) + @staticmethod + async def get_template_type(data): + if type(data) not in {dict, list, set, tuple}: + raise TypeError("template variables for template_body and message.html must be of type list, tuple, set " + f"or dict - {type(data)} is invalid") + return type(data) + async def __prepare_message(self, message: MessageSchema, template=None): if template is not None: template_body = message.template_body if template_body and not message.html: - message.template_body = template.render(body=template_body) + if self.get_template_type(template_body) == dict: + message.template_body = template.render(**template_body) + else: + message.template_body = template.render(*template_body) message.subtype = "html" elif message.html: - message.html = template.render(body=message.html) + if self.get_template_type(message.html) == dict: + message.html = template.render(**message.html) + else: + message.html = template.render(*message.html) msg = MailMsg(**message.dict()) if self.config.MAIL_FROM_NAME is not None: From b14eabc17541e0be01ca3bc697da1f2c977ce31d Mon Sep 17 00:00:00 2001 From: Floodpants Date: Sat, 24 Jul 2021 18:54:51 +1000 Subject: [PATCH 2/3] simplify approach to dict rendering for Jinja template --- fastapi_mail/fastmail.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/fastapi_mail/fastmail.py b/fastapi_mail/fastmail.py index 071b3ac..33ecefa 100755 --- a/fastapi_mail/fastmail.py +++ b/fastapi_mail/fastmail.py @@ -39,12 +39,12 @@ def _record(message): class FastMail(_MailMixin): - ''' + """ Fastapi mail system sending mails(individual, bulk) attachments(individual, bulk) :param config: Connection config to be passed - ''' + """ def __init__(self, config: ConnectionConfig @@ -56,26 +56,22 @@ async def get_mail_template(self, env_path, template_name): return env_path.get_template(template_name) @staticmethod - async def get_template_type(data): - if type(data) not in {dict, list, set, tuple}: - raise TypeError("template variables for template_body and message.html must be of type list, tuple, set " - f"or dict - {type(data)} is invalid") - return type(data) + def make_dict(data): + try: + return dict(data) + except ValueError: + raise ValueError(f"Unable to build template data dictionary - {type(data)} is an invalid source data type") async def __prepare_message(self, message: MessageSchema, template=None): if template is not None: template_body = message.template_body if template_body and not message.html: - if self.get_template_type(template_body) == dict: - message.template_body = template.render(**template_body) - else: - message.template_body = template.render(*template_body) + template_data = self.make_dict(template_body) + message.template_body = template.render(**template_data) message.subtype = "html" elif message.html: - if self.get_template_type(message.html) == dict: - message.html = template.render(**message.html) - else: - message.html = template.render(*message.html) + template_data = self.make_dict(message.html) + message.html = template.render(**template_data) msg = MailMsg(**message.dict()) if self.config.MAIL_FROM_NAME is not None: From 449079d4c5fd25cc44ef818daca0e694f6e28688 Mon Sep 17 00:00:00 2001 From: Floodpants Date: Sat, 7 Aug 2021 15:01:41 +1000 Subject: [PATCH 3/3] update docs around the dict that gets passed to Jinja --- docs/example.md | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/docs/example.md b/docs/example.md index 1140886..e505b29 100644 --- a/docs/example.md +++ b/docs/example.md @@ -30,7 +30,7 @@ conf = ConnectionConfig( MAIL_FROM = "your@email.com", MAIL_PORT = 587, MAIL_SERVER = "your mail server", - MAIL_FROM_NAME="Desired Name" + MAIL_FROM_NAME="Desired Name", MAIL_TLS = True, MAIL_SSL = False, USE_CREDENTIALS = True, @@ -117,6 +117,10 @@ async def send_file( ### Using Jinja2 HTML Templates +You can enable Jinja2 HTML Template emails by setting the `TEMPLATE_FOLDER` configuration option, and supplying a +value (which is just the name of the template file within the `TEMPLATE_FOLDER` dir) for the `template_name` parameter +in `FastMail.send_message()`. You then can pass a Dict as the `template_body` property of your `MessageSchema` object: + ```python class EmailSchema(BaseModel): @@ -151,6 +155,37 @@ async def send_with_template(email: EmailSchema) -> JSONResponse: ``` +For example, assume we pass a `template_body` of: + +```json +{ + "first_name": "Fred", + "last_name": "Fredsson" +} +``` + +We can reference the variables in our Jinja templates as per normal: + +``` +... +Hello, {{ first_name }}! +... +``` + +#### Legacy Behaviour (<= 0.4.0) + +The original behaviour in <= 0.4.0 was to wrap the Dict you provide in a variable named `body` when it was provided to +Jinja behind the scenes. In these versions, you can then access your dict in your template like so: + +``` +... +Hello, {{ body.first_name }}! +... +``` + +As you can see our keys in our dict are no longer the top level, they are part of the `body` variable. Nesting works +as per normal below this level also. + ## Guide for email utils The utility allows you to check temporary email addresses, you can block any email or domain.