sabuhish / fastapi-mail

Fastapi mail system sending mails(individual, bulk) attachments(individual, bulk)
https://sabuhish.github.io/fastapi-mail/
MIT License
673 stars 82 forks source link

How to send email as Jinja template with image? #173

Open morento101 opened 1 year ago

morento101 commented 1 year ago

I use FastAPI-Mail and Celery to send notifications in the background. I want to place the static image in the template and send it to the customer.

I discovered that a url_for function returns an absolute URL and can be used in img tag as src.

image

The problem is that I get such an error, and I don't know how to solve it:

Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/celery/app/trace.py", line 451, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/usr/local/lib/python3.10/site-packages/celery/app/trace.py", line 734, in __protected_call__
    return self.run(*args, **kwargs)
  File "/code/app/tasks/worker.py", line 17, in create_task
    send_birthday_reminder(
  File "/usr/local/lib/python3.10/site-packages/asgiref/sync.py", line 218, in __call__
    return call_result.result()
  File "/usr/local/lib/python3.10/concurrent/futures/_base.py", line 451, in result
    return self.__get_result()
  File "/usr/local/lib/python3.10/concurrent/futures/_base.py", line 403, in __get_result
    raise self._exception
  File "/usr/local/lib/python3.10/site-packages/asgiref/sync.py", line 284, in main_wrap
    result = await self.awaitable(*args, **kwargs)
  File "/code/app/email/email.py", line 29, in send_birthday_reminder
    await fm.send_message(
  File "/usr/local/lib/python3.10/site-packages/fastapi_mail/fastmail.py", line 105, in send_message
    msg = await self.__prepare_message(message, template)
  File "/usr/local/lib/python3.10/site-packages/fastapi_mail/fastmail.py", line 71, in __prepare_message
    message.template_body = await self.__template_message_builder(
  File "/usr/local/lib/python3.10/site-packages/fastapi_mail/fastmail.py", line 85, in __template_message_builder
    return template.render(**template_data)
  File "/usr/local/lib/python3.10/site-packages/jinja2/environment.py", line 1301, in render
    self.environment.handle_exception()
  File "/usr/local/lib/python3.10/site-packages/jinja2/environment.py", line 936, in handle_exception
    raise rewrite_traceback_stack(source=source)
  File "/code/app/templates/email/birthday_reminder.html", line 1, in top-level template code
    {% extends './base.html' %}
  File "/code/app/templates/base.html", line 11, in top-level template code
    {% block content %} {% endblock %}
  File "/code/app/templates/email/birthday_reminder.html", line 4, in block 'content'
    <img src="{{ url_for('static', path='img/birthday_alarm.png') }}" />
  File "/usr/local/lib/python3.10/site-packages/jinja2/utils.py", line 83, in from_obj
    if hasattr(obj, "jinja_pass_arg"):
jinja2.exceptions.UndefinedError: 'url_for' is undefined

How can I solve this issue? Is there a better way to send a template with an image?

morento101 commented 1 year ago

Celery worker file worker.py

from celery import Celery

from app.core.config import settings
from app.email.email import send_birthday_reminder

celery = Celery(__name__)
celery.conf.broker_url = settings.CELERY_BROKER_URL
celery.conf.result_backend = settings.CELERY_RESULT_BACKEND

@celery.task(name="create_task")
def create_task():
    send_birthday_reminder(
        'customer@gmail.com', {"subject": "hi"}
    )

File for sending emails email.py

from asgiref.sync import async_to_sync
from fastapi_mail import ConnectionConfig, FastMail, MessageSchema

from app.core.config import BASE_DIR, settings

conf = ConnectionConfig(
    MAIL_USERNAME=settings.MAIL_USERNAME,
    MAIL_PASSWORD=settings.MAIL_PASSWORD,
    MAIL_FROM=settings.MAIL_FROM,
    MAIL_PORT=settings.MAIL_PORT,
    MAIL_SERVER=settings.MAIL_SERVER,
    MAIL_STARTTLS=False,
    MAIL_SSL_TLS=False,
    USE_CREDENTIALS=True,
    TEMPLATE_FOLDER=BASE_DIR / 'templates'
)

@async_to_sync
async def send_birthday_reminder(email_to: str, content: dict):
    message = MessageSchema(
        subject='Birthday Reminder',
        recipients=[email_to],
        template_body=content,
        subtype='html',
    )

    fm = FastMail(conf)
    await fm.send_message(
        message, template_name='email/birthday_reminder.html'
    )
sabuhish commented 1 year ago

Hi @morento101, I would suggest you use S3 or any other bucket that way it is much more useful I feel.

LuckyLub commented 10 months ago

@morento101 I am adding images to templates as described here: Customizing attachments by headers and MIME type