# Alternative EMAIL\_BACKEND

**URL:** <https://discuss.openedx.org/t/alternative-email-backend/13878>\
**Category:** Site Operators\
**Tags:** how-to, tutor\
**Created:** [September 9, 2024, 5:25am UTC](https://discuss.openedx.org/t/alternative-email-backend/13878 "2024-09-09T05:25:36Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![venturafranklin](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/venturafranklin/32/7333_2.png) [@venturafranklin](https://discuss.openedx.org/u/venturafranklin)\
**Post date:** [September 9, 2024, 5:25am UTC](https://discuss.openedx.org/t/alternative-email-backend/13878/1 "2024-09-09T05:25:36Z")

</div>

Would it be possible to setup an email backend other than `django.core.mail.backends.smtp.EmailBackend` specifically, I am trying to use `anymail.backends.mailjet.EmailBackend`.

I have tried to set the `EMAIL_BACKEND` in the config.yml and the cms.env.yml and lms.env.yml files but this does not seem to get picked up by a build and/or restart of tutor. I was able to add the `OPENEDX_EXTRA_PIP_REQUIREMENTS` to install django-anymail but that doesn’t help if I can’t override the backend setting.

After a build I still see the EMAIL\_BACKEND are pointed to smtp

```auto
app@b1a127346f80:~/edx-platform$ grep -rnw . -e "EMAIL_BACKEND"
./cms/envs/devstack-experimental.yml:283:EMAIL_BACKEND: django.core.mail.backends.smtp.EmailBackend
./cms/envs/common.py:1265:EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
./cms/envs/devstack.py:41:EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
Binary file ./cms/envs/ __pycache__ /common.cpython-311.pyc matches
./lms/envs/devstack-experimental.yml:307:EMAIL_BACKEND: django.core.mail.backends.smtp.EmailBackend
./lms/envs/common.py:1913:EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
./lms/envs/devstack.py:69:EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'

```

This is what my configs look like

```auto
frank_ventura@edx-tutor:~/.local/share$ grep -rnw . -e "EMAIL_BACKEND"
./tutor/config.yml:4:EMAIL_BACKEND: anymail.backends.mailjet.EmailBackend
./tutor/env/apps/openedx/config/cms.env.yml:37:EMAIL_BACKEND: anymail.backends.mailjet.EmailBackend
./tutor/env/apps/openedx/config/lms.env.yml:44:EMAIL_BACKEND: anymail.backends.mailjet.EmailBackend

```

Is it possible to use a different email backend?

---

<div class="post-metadata">

**Author:** ![Syed\_Muhammad\_Dawoud](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/syed_muhammad_dawoud/32/6313_2.png) [@Syed\_Muhammad\_Dawoud](https://discuss.openedx.org/u/Syed_Muhammad_Dawoud)\
**Post date:** [September 9, 2024, 7:03am UTC](https://discuss.openedx.org/t/alternative-email-backend/13878/2 "2024-09-09T07:03:40Z")

</div>

how are you adding values to cms.env and lms.env yaml files? If you are editing the files directly in env, they will be overwritten on config save. You should be using a plugin to do that [Configuration and customisation — Tutor documentation](https://docs.tutor.edly.io/configuration.html#configuration-and-customisation)

---

<div class="post-metadata">

**Author:** ![venturafranklin](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/venturafranklin/32/7333_2.png) [@venturafranklin](https://discuss.openedx.org/u/venturafranklin)\
**Post date:** [September 9, 2024, 2:03pm UTC](https://discuss.openedx.org/t/alternative-email-backend/13878/3 "2024-09-09T14:03:51Z")

</div>

Yes, I have a plugin that looks like:

```auto
from tutor import hooks

hooks.Filters.CONFIG_USER.add_item(
    ("EMAIL_BACKEND", "anymail.backends.mailjet.EmailBackend"),
)

hooks.Filters.CONFIG_OVERRIDES.add_item(
    ("EMAIL_BACKEND", "anymail.backends.mailjet.EmailBackend"),
)

hooks.Filters.ENV_PATCHES.add_items(
    [
        ("cms-env", "EMAIL_BACKEND: anymail.backends.mailjet.EmailBackend"),
        ("lms-env", "EMAIL_BACKEND: anymail.backends.mailjet.EmailBackend"),
    ]
)

```

However, I do find that the `CONFIG_OVERRIDES` does not seem to override a config in those cms.env and lms.env yaml files like I would think it should. Instead, the `ENV_PATCHES` adds it and I had manually removed the old values.

---

<div class="post-metadata">

**Author:** ![venturafranklin](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/venturafranklin/32/7333_2.png) [@venturafranklin](https://discuss.openedx.org/u/venturafranklin)\
**Post date:** [September 14, 2024, 7:17pm UTC](https://discuss.openedx.org/t/alternative-email-backend/13878/4 "2024-09-14T19:17:15Z")

</div>

I think I made some progress. I needed to add `("RUN_SMTP", False),` to the CONFIG\_USER

```auto
hooks.Filters.CONFIG_USER.add_items(
    [
        ("EMAIL_BACKEND", "anymail.backends.mailjet.EmailBackend"),
        ("RUN_SMTP", False),
    ]
)

```

And then add the settings

```auto
hooks.Filters.ENV_PATCHES.add_items(
    [
        ("cms-env", "EMAIL_BACKEND: anymail.backends.mailjet.EmailBackend"),
        ("lms-env", "EMAIL_BACKEND: anymail.backends.mailjet.EmailBackend"),
        ("cms-env", "MAILJET_API_KEY: MAILJET_API_KEY"),
        ("lms-env", "MAILJET_API_KEY: MAILJET_API_KEY"),
        ("cms-env", "MAILJET_SECRET_KEY: MAILJET_SECRET_KEY"),
        ("lms-env", "MAILJET_SECRET_KEY: MAILJET_SECRET_KEY"),
    ]
)

```

I have verified that anymail should be installed, it is in the config.yml after I ran `tutor config save --append OPENEDX_EXTRA_PIP_REQUIREMENTS=django-anymail[mailjet]==8.6`

And a grep of the docker shows it is there, `cat ~/.local/share/tutor/env/build/openedx/Dockerfile | grep mail`

After a disable, enable of the plugin, re build of the openedx with `tutor images build openedx --no-cache` I watch and see that django-anymail is installed.

And I can run the command successfully from command line. This command works and I get the email:  
`tutor local run --no-deps lms ./manage.py lms shell -c "from django.core.mail import send_mail; send_mail('test subject', 'test message', 'test@test.org', ['me@gmail.com'])"`

However, when I bash into the LMS image with `sudo docker exec -it tutor_local-lms-1 bash` and go a `pip freeze | grep anymail` I get no results like anymail was not installed. Or maybe I misunderstand how the extra pip installation works? And trying to send an email to a user in the frontend results in the error below:

```auto
lms-1 | [pid: 1|app: 0|req: 16/33] 172.18.0.7 () {66 vars in 2842 bytes} [Sat Sep 14 19:12:02 2024] POST /courses/course-v1:ThetaTau+TT101+intro/instructor/api/list_instructor_tasks => generated 17 bytes in 67 msecs (HTTP/1.1 200) 10 headers in 607 bytes (1 switches on core 0)
lms-1 | 2024-09-14 19:12:04,835 INFO 15 [tracking] [user 4] [ip 172.110.170.18] logger.py:41 - {"name": "/courses/course-v1:ThetaTau+TT101+intro/instructor/api/students_update_enrollment", "context": {"course_id": "course-v1:ThetaTau+TT101+intro", "course_user_tags": {}, "user_id": 4, "path": "/courses/course-v1:ThetaTau+TT101+intro/instructor/api/students_update_enrollment", "org_id": "ThetaTau", "enterprise_uuid": ""}, "username": "frank.ventura@thetatau.org", "session": "7145a02b62697f10e29542f8242076b3", "ip": "172.110.170.18", "agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36", "host": "ed.thetatau.org", "referer": "https://ed.thetatau.org/courses/course-v1:ThetaTau+TT101+intro/instructor", "accept_language": "en-US,en;q=0.9", "event": "{\"GET\": {}, \"POST\": {\"action\": [\"enroll\"], \"identifiers\": [\"frank.ventura+1234@thetatau.org\"], \"auto_enroll\": [\"true\"], \"email_students\": [\"true\"]}}", "time": "2024-09-14T19:12:04.835549+00:00", "event_type": "/courses/course-v1:ThetaTau+TT101+intro/instructor/api/students_update_enrollment", "event_source": "server", "page": null}
lms-1 | 2024-09-14 19:12:04,944 ERROR 15 [lms.djangoapps.instructor.views.api] [user 4] [ip 172.110.170.18] api.py:873 - Error while #{}ing student
lms-1 | Traceback (most recent call last):
lms-1 | File "/openedx/edx-platform/lms/djangoapps/instructor/views/api.py", line 819, in students_update_enrollment
lms-1 | before, after, enrollment_obj = enroll_email(
lms-1 | ^^^^^^^^^^^^^
lms-1 | File "/openedx/edx-platform/lms/djangoapps/instructor/enrollment.py", line 177, in enroll_email
lms-1 | send_mail_to_student(student_email, email_params, language=language)
lms-1 | File "/openedx/edx-platform/lms/djangoapps/instructor/enrollment.py", line 561, in send_mail_to_student
lms-1 | ace.send(message)
lms-1 | File "/openedx/venv/lib/python3.11/site-packages/edx_ace/ace.py", line 53, in send
lms-1 | delivery.deliver(channel, rendered_message, msg)
lms-1 | File "/openedx/venv/lib/python3.11/site-packages/edx_ace/delivery.py", line 51, in deliver
lms-1 | channel.deliver(message, rendered_message)
lms-1 | File "/openedx/venv/lib/python3.11/site-packages/edx_ace/channel/django_email.py", line 68, in deliver
lms-1 | mail.send()
lms-1 | File "/openedx/venv/lib/python3.11/site-packages/django/core/mail/message.py", line 299, in send
lms-1 | return self.get_connection(fail_silently).send_messages([self])
lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lms-1 | File "/openedx/venv/lib/python3.11/site-packages/django/core/mail/message.py", line 256, in get_connection
lms-1 | self.connection = get_connection(fail_silently=fail_silently)
lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lms-1 | File "/openedx/venv/lib/python3.11/site-packages/django/core/mail/ __init__.py", line 50, in get_connection
lms-1 | klass = import_string(backend or settings.EMAIL_BACKEND)
lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lms-1 | File "/openedx/venv/lib/python3.11/site-packages/django/utils/module_loading.py", line 30, in import_string
lms-1 | return cached_import(module_path, class_name)
lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lms-1 | File "/openedx/venv/lib/python3.11/site-packages/django/utils/module_loading.py", line 15, in cached_import
lms-1 | module = import_module(module_path)
lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^
lms-1 | File "/opt/pyenv/versions/3.11.8/lib/python3.11/importlib/ __init__.py", line 126, in import_module
lms-1 | return _bootstrap._gcd_import(name[level:], package, level)
lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lms-1 | File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
lms-1 | File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
lms-1 | File "<frozen importlib._bootstrap>", line 1126, in _find_and_load_unlocked
lms-1 | File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
lms-1 | File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
lms-1 | File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
lms-1 | File "<frozen importlib._bootstrap>", line 1126, in _find_and_load_unlocked
lms-1 | File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
lms-1 | File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
lms-1 | File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
lms-1 | File "<frozen importlib._bootstrap>", line 1140, in _find_and_load_unlocked
lms-1 | ModuleNotFoundError: No module named 'anymail'
lms-1 | 2024-09-14 19:12:04,948 ERROR 15 [lms.djangoapps.instructor.views.api] [user 4] [ip 172.110.170.18] api.py:874 - No module named 'anymail'
lms-1 | Traceback (most recent call last):
lms-1 | File "/openedx/edx-platform/lms/djangoapps/instructor/views/api.py", line 819, in students_update_enrollment
lms-1 | before, after, enrollment_obj = enroll_email(
lms-1 | ^^^^^^^^^^^^^
lms-1 | File "/openedx/edx-platform/lms/djangoapps/instructor/enrollment.py", line 177, in enroll_email
lms-1 | send_mail_to_student(student_email, email_params, language=language)
lms-1 | File "/openedx/edx-platform/lms/djangoapps/instructor/enrollment.py", line 561, in send_mail_to_student
lms-1 | ace.send(message)
lms-1 | File "/openedx/venv/lib/python3.11/site-packages/edx_ace/ace.py", line 53, in send
lms-1 | delivery.deliver(channel, rendered_message, msg)
lms-1 | File "/openedx/venv/lib/python3.11/site-packages/edx_ace/delivery.py", line 51, in deliver
lms-1 | channel.deliver(message, rendered_message)
lms-1 | File "/openedx/venv/lib/python3.11/site-packages/edx_ace/channel/django_email.py", line 68, in deliver
lms-1 | mail.send()
lms-1 | File "/openedx/venv/lib/python3.11/site-packages/django/core/mail/message.py", line 299, in send
lms-1 | return self.get_connection(fail_silently).send_messages([self])
lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lms-1 | File "/openedx/venv/lib/python3.11/site-packages/django/core/mail/message.py", line 256, in get_connection
lms-1 | self.connection = get_connection(fail_silently=fail_silently)
lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lms-1 | File "/openedx/venv/lib/python3.11/site-packages/django/core/mail/ __init__.py", line 50, in get_connection
lms-1 | klass = import_string(backend or settings.EMAIL_BACKEND)
lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lms-1 | File "/openedx/venv/lib/python3.11/site-packages/django/utils/module_loading.py", line 30, in import_string
lms-1 | return cached_import(module_path, class_name)
lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lms-1 | File "/openedx/venv/lib/python3.11/site-packages/django/utils/module_loading.py", line 15, in cached_import
lms-1 | module = import_module(module_path)
lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^
lms-1 | File "/opt/pyenv/versions/3.11.8/lib/python3.11/importlib/ __init__.py", line 126, in import_module
lms-1 | return _bootstrap._gcd_import(name[level:], package, level)
lms-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lms-1 | File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
lms-1 | File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
lms-1 | File "<frozen importlib._bootstrap>", line 1126, in _find_and_load_unlocked
lms-1 | File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
lms-1 | File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
lms-1 | File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
lms-1 | File "<frozen importlib._bootstrap>", line 1126, in _find_and_load_unlocked
lms-1 | File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
lms-1 | File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
lms-1 | File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
lms-1 | File "<frozen importlib._bootstrap>", line 1140, in _find_and_load_unlocked
lms-1 | ModuleNotFoundError: No module named 'anymail'
lms-1 | [pid: 15|app: 0|req: 16/34] 172.18.0.7 () {68 vars in 2917 bytes} [Sat Sep 14 19:12:04 2024] POST /courses/course-v1:ThetaTau+TT101+intro/instructor/api/students_update_enrollment => generated 154 bytes in 150 msecs (HTTP/1.1 200) 10 headers in 608 bytes (1 switches on core 0)

```

What am I doing wrong with the OPENEDX\_EXTRA\_PIP\_REQUIREMENTS and then seeing that in the container of the LMS?

---

<div class="post-metadata">

**Author:** ![venturafranklin](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/venturafranklin/32/7333_2.png) [@venturafranklin](https://discuss.openedx.org/u/venturafranklin)\
**Post date:** [September 14, 2024, 8:08pm UTC](https://discuss.openedx.org/t/alternative-email-backend/13878/5 "2024-09-14T20:08:39Z")

</div>

If inside the container with  
`sudo docker exec -it tutor_local-lms-1 bash`  
and I run  
`pip install django-anymail[mailjet]==8.6`  
the LMS can send emails just fine.

---

<div class="post-metadata">

**Author:** ![venturafranklin](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.openedx.org/venturafranklin/32/7333_2.png) [@venturafranklin](https://discuss.openedx.org/u/venturafranklin)\
**Post date:** [September 15, 2024, 3:30pm UTC](https://discuss.openedx.org/t/alternative-email-backend/13878/6 "2024-09-15T15:30:46Z")

</div>

It looks like this whole time I have been running  
`tutor local restart`  
This does NOT seem to pick up the new build. I needed to run:  
`tutor local launch`  
And now the email through Mailjet seems to be working.
