# django-heralder
[](https://pypi.python.org/pypi/django-heralder)
[](https://github.com/peterfarrell/django-heralder/actions/workflows/ci.yml)
[](https://github.com/peterfarrell/django-heralder/actions/workflows/black.yml)
[](https://codecov.io/gh/peterfarrell/django-heralder)
[](https://github.com/peterfarrell/django-heralder)
A Django messaging library that features:
- Class-based declaration and registry approach, like Django Admin
- Supports multiple transmission methods (Email, SMS, Slack, etc) per message
- Browser-based previewing of messages
- Maintains a history of messaging sending attempts and can view these messages
- Disabling notifications per user
- Auto conversion of HTML emails to text versions
## History
Django-Heralder is a fork of the legacy [Django-Herald](https://github.com/worthwhile/django-herald).
The `v0.3.0` release of Django-Herald has the same features and is equal to Django-Heralder `v0.3.0`.
As of Django-Heralder `v0.4.0`, Django-Heralder has diverged from original project with new features and bug fixes.
## Installation
### Supported Django / Python Versions
We try to make Heralder support all versions of django that django supports + all versions in between.
For python, Heralder supports all versions of python that the above versions of django support.
As of Heralder v0.4.0, we support:
| Django | Python `3.9` | Python `3.10` | Python `3.11` | Python `3.12` | Python `3.13` |
| --- | --- | --- | --- | --- | --- |
| `3.2.x` | **Y** | **Y** | - | - | - |
| `4.2.x` | **Y** | **Y** | **Y** | **Y** | - |
| `5.2.x` | - | **Y** | **Y** | **Y** | **Y** |
### Installation
1. Install Django-Heralder using your favority packagement management tool (e.g. `pip`, `uv`, etc.)
```bash
pip install django-heralder
```
2. In your `settings.py` file, add `herald` and `django.contrib.sites` to `INSTALLED_APPS`:
```python
# ... other settings ...
INSTALLED_APPS = [
# ... other apps ...
'herald',
'django.contrib.sites',
]
```
3. In your main project `urls.py` file, add Heralder's URL routes:
```python
from django.conf import settings
from django.conf.urls import url, include
urlpatterns = []
if settings.DEBUG:
urlpatterns = [
url(r'^herald/', include('herald.urls')),
] + urlpatterns
```
## Example Usage
1. Create a `notifications.py` file in any django app. This is where your notification classes will live. Add a class like this:
```python
from herald import registry
from herald.base import EmailNotification
class WelcomeEmail(EmailNotification): # extend from EmailNotification for emails
template_name = 'welcome_email' # name of template, without extension
subject = 'Welcome' # subject of email
def __init__(self, user): # optionally customize the initialization
self.context = {'user': user} # set context for the template rendering
self.to_emails = [user.email] # set list of emails to send to
@staticmethod
def get_demo_args(): # define a static method to return list of args needed to initialize class for testing
from users.models import User
return [User.objects.order_by('?')[0]]
registry.register(WelcomeEmail) # finally, register your notification class
# Alternatively, a class decorator can be used to register the notification:
@registry.register_decorator()
class WelcomeEmail(EmailNotification):
# ... more code ...
```
2. Create templates for rendering the email using this file structure:
```text
templates/
herald/
text/
welcome_email.txt
html/
welcome_email.html
```
3. Test how your email looks by navigating to `/herald/`.
4. Additionally, preview your email before you send:
```python
WelcomeEmail().preview(render_type="html")
```
5. Send your email wherever you need in your code:
```python
WelcomeEmail(user).send()
```
6. View the sent emails in django admin and even be able to resend it.
## Setting template names
There's three different ways to specify `templatename`:
1. A string without any slash, e.g. `"welcome_email"` and Herald will expect your file structure to be:
```text
templates/
herald/
text/
welcome_email.txt
html/
welcome_email.html
```
2. A string with slashes, e.g. `"path/to/welcome_email"` and Herald will expect your file structure to be:
```text
templates/
path/
to/
welcome_email.txt
welcome_email.html
```
3. A dictionary with `text` and/or `html` keys with the path to the templates:
```python
{
"text": "path/to/welcome_email_t.txt",
"html": "path/to/welcome_email_h.html",
}
```
and Herald will expect your file structure to be:
```text
templates/
path/
to/
welcome_email_t.txt
welcome_email_h.html
```
## Email options
The following options can be set on the email notification class. For Example:
```python
class WelcomeEmail(EmailNotification):
cc = ['test@example.com']
```
- `from_email`: (`str`, default: `settings.DEFAULT_FROM_EMAIL`) email address of sender
- `subject`: (`str`, default: ) email subject
- `to_emails`: (`List[str]`, default: `None`) list of email strings to send to
- `bcc`: (`List[str]`, default: `None`) list of email strings to send as bcc
- `cc`: (`List[str]`, default: `None`) list of email strings to send as cc
- `headers`: (`dict`, default: `None`) extra headers to be passed along to the `EmailMultiAlternatives` object
- `reply_to`: (`List[str]`, default: `None`) list of email strings to send as the Reply-To emails
- `attachments`: (`list`) list of attachments. See "Email Attachments" below for more info
## Automatically Deleting Old Notifications
Herald can automatically delete old notifications whenever a new notification is sent.
To enable this, set the `HERALD_NOTIFICATION_RETENTION_TIME` setting to a timedelta instance.
For example:
```python
HERALD_NOTIFICATION_RETENTION_TIME = timedelta(weeks=8)
```
Will delete all notifications older than 8 weeks every time a new notification is sent.
## Manually Deleting Old Notifications
The `delnotifs` command is useful for purging the notification history.
The default usage will delete everything from sent during today:
```bash
python manage.py delnotifs
```
However, you can also pass arguments for `start` or `end` dates. `end` is up to, but not including that date.
- if only `end` is specified, delete anything sent before the end date.
- if only `start` is specified, delete anything sent since the start date.
- if both `start` and `end` are specified, delete anything sent in between, not including the end date.
```bash
python manage.py delnotifs --start='2016-01-01' --end='2016-01-10'
```
## Asynchronous Email Sending
If you are sending slightly different emails to a large number of people, it might take quite a while to process. By default, Django will process this all synchronously. For asynchronous support, we recommend django-celery-email. It is very straightfoward to setup and integrate: https://github.com/pmclanahan/django-celery-email
## Custom SentNotification Model
To create a custom `SentNotification` model, inherit `SentNotificationAbstract`. From there you can add fields and methods as desired. To use this model through Heralder, set `HERALD_SENT_NOTIFICATION_MODEL` in your `settings.py` to the `app.ModelName` path. Then use `get_sent_notification_model` in `herald.utils` to retrieve the model.
Note that using a custom model should be implemented as early as possible, ideally at the beginning of the project. Otherwise data may be split between the default table and the newly created custom table. To mitigate this, data will have to either be dropped or migrated to the new table.
Example:
```python
from herald.models import SentNotificationAbstract
class SentNotificationCompany(SentNotificationAbstract):
company_name = models.CharField(max_length=32)
class Meta(SentNotificationAbstract.Meta):
abstract = False
```
In `settings.py`:
```python
HERALD_SENT_NOTIFICATION_MODEL = "mpapp.SentNotificationCompany"
```
Using throughout your app:
```python
from herald.utils import get_sent_notification_model
SentNotification = get_sent_notification_model()
```
## herald.contrib.auth
Django has built-in support for sending password reset emails. If you would like to send those emails using herald, you can use the notification class in herald.contrib.auth.
First, add `herald.contrib.auth` to `INSTALLED_APPS` (in addition to `herald`).
Second, use the `HeraldPasswordResetForm` in place of django's built in `PasswordResetForm`. This step is entirely dependant on your project structure, but it essentially just involves changing the form class on the password reset view in some way:
```python
# you may simply just need to override the password reset url like so:
url(r'^password_reset/$', password_reset, name='password_reset', {'password_reset_form': HeraldPasswordResetForm}),
# of if you are using something like django-authtools:
url(r'^password_reset/$', PasswordResetView.as_view(form_class=HeraldPasswordResetForm), name='password_reset'),
# or you may have a customized version of the password reset view:
class MyPasswordResetView(FormView):
form_class = HeraldPasswordResetForm # change the form class here
# or, you may have a custom password reset form already. In that case, you will want to extend from the HeraldPasswordResetForm:
class MyPasswordResetForm(HeraldPasswordResetForm):
...
# alternatively, you could even just send the notification wherever you wish, seperate from the form:
PasswordResetEmail(some_user).send()
```
Third, you may want to customize the templates for the email. By default, herald will use the `registration/password_reset_email.html` that is provided by django for both the html and text versions of the email. But you can simply override `herald/html/password_reset.html` and/or `herald/text/password_reset.txt` to suit your needs.
## User Disabled Notifications
If you want to disable certain notifications per user, add a record to the UserNotification table and
add notifications to the disabled_notifications many to many table.
For example:
```python
user = User.objects.get(id=user.id)
notification = Notification.objects.get(notification_class=MyNotification.get_class_path())
# disable the notification
user.usernotification.disabled_notifications.add(notification)
```
By default, notifications can be disabled. You can put can_disable = False in your notification class and the system will populate the database with this default. Your Notification class can also override the verbose_name by setting it in your inherited Notification class. Like this:
```python
class MyNotification(EmailNotification):
can_disable = False
verbose_name = "My Required Notification"
```
## Email Attachments
To send attachments, assign a list of attachments to the attachments attribute of your EmailNotification instance, or override the get_attachments() method.
Each attachment in the list can be one of the following:
1. A tuple which consists of the filename, the raw attachment data, and the mimetype. It is up to you to get the attachment data. Like this:
```python
raw_data = get_pdf_data()
email.attachments = [
('Report.pdf', raw_data, 'application/pdf'),
('report.txt', 'text version of report', 'text/plain')
]
email.send()
```
2. A MIMEBase object. See the documentation for attachments under EmailMessage Objects/attachments in the Django documentation.
3. A django `File` object.
### Inline Attachments
Sometimes you want to embed an image directly into the email content. Do that by using a MIMEImage assigning a content id header to a MIMEImage, like this:
```python
email = WelcomeEmail(user)
im = get_thumbnail(image_file.name, '600x600', quality=95)
my_image = MIMEImage(im.read()) # MIMEImage inherits from MIMEBase
my_image.add_header('Content-ID', '<{}>'.format(image_file.name))
```
You can refer to these images in your html email templates using the Content ID (cid) like this:
```html
<img src="cid:{{image_file.name}}" />
```
You would of course need to add the "image_file" to your template context in the example above. You can also accomplish this using file operations. In this example we overrode the get_attachments method of an EmailNotification.
```python
class MyNotification(EmailNotification):
context = {'hello': 'world'}
template_name = 'welcome_email'
to_emails = ['somebody@example.com']
subject = "My email test"
def get_attachments(self):
fp = open('python.jpeg', 'rb')
img = MIMEImage(fp.read())
img.add_header('Content-ID', '<{}>'.format('python.jpeg'))
return [
img,
]
```
And in your template you would refer to it like this, and you would not need to add anything to the context:
```html
<img src="cid:python.jpeg" />
```
### Missing Templates
By default, Heralder will raise an exception if a template is missing when true (default).
```python
HERALD_RAISE_MISSING_TEMPLATES = True
```
If you do not want this behavior, set this setting to False.
```python
HERALD_RAISE_MISSING_TEMPLATES = False
```
### HTML2Text Support
Django Herald can auto convert your HTML emails to plain text when installed with `hmtl2text` optional package. Any email without a plain text version will be auto converted if you enable this feature.
1. Install Heralder with `html2text` support:
```bash
pip install django-heralder[html2text]
```
2. Follow the regular installation instructions.
3. In your `settings.py` file, add this configuration setting to enable the `html2text` feature:
```python
HERALD_HTML2TEXT_ENABLED = True
```
4. You can customize the output of HTML2Text by setting a configuration dictionary. See [HTML2Text Configuration](https://github.com/Alir3z4/html2text/blob/master/docs/usage.md) for options:
```python
HERALD_HTML2TEXT_CONFIG = {
# Key / value configuration of html2text
'ignore_images': True # Ignores images in conversion
}
```
### Twilio
Heralder supports Twilio as a notification provider when the optional package is installed.
1. Install Heralder with `twilio` support:
```bash
pip install django-heralder[twilio]
```
2. Follow the regular installation instructions.
3. In your `settings.py` file, set your Twilio account SID, token, and default "from number". You can retrieve these values on [Twilio Console](https://twilio.com/console). Security best practices recommend to NOT hard coding your SID or token in your source code. The example below:
```python
# Twilio configurations
# values taken from `twilio console`
TWILIO_ACCOUNT_SID = "your_account_sid"
TWILIO_AUTH_TOKEN = "your_auth_token"
TWILIO_DEFAULT_FROM_NUMBER = "+1234567890"
```
For reference, Twilio has some great tutorials for Python: [Twilio Python Tutorial](https://www.twilio.com/docs/sms/quickstart/python)
### Other MIME attachments
You can also attach any MIMEBase objects as regular attachments, but you must add a content-disposition header, or they will be inaccessible:
```python
my_image.add_header('Content-Disposition', 'attachment; filename="python.jpg"')
```
Attachments can cause your database to become quite large, so you should be sure to run the management commands to purge the database of old messages.
Raw data
{
"_id": null,
"home_page": "https://github.com/peterfarrell/django-heralder/",
"name": "django-heralder",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": "django, notifications, messaging",
"author": "PJ Farrell",
"author_email": "pjf@maepub.com",
"download_url": "https://files.pythonhosted.org/packages/a5/2b/2015fc133ac822bbf0dd428cadaa77ce6653be968109d6a357e4f4ae4f1f/django_heralder-0.4.1.tar.gz",
"platform": null,
"description": "# django-heralder\n\n[](https://pypi.python.org/pypi/django-heralder)\n[](https://github.com/peterfarrell/django-heralder/actions/workflows/ci.yml)\n[](https://github.com/peterfarrell/django-heralder/actions/workflows/black.yml)\n[](https://codecov.io/gh/peterfarrell/django-heralder)\n\n[](https://github.com/peterfarrell/django-heralder)\n\nA Django messaging library that features:\n\n- Class-based declaration and registry approach, like Django Admin\n- Supports multiple transmission methods (Email, SMS, Slack, etc) per message\n- Browser-based previewing of messages\n- Maintains a history of messaging sending attempts and can view these messages\n- Disabling notifications per user\n- Auto conversion of HTML emails to text versions\n\n## History\n\nDjango-Heralder is a fork of the legacy [Django-Herald](https://github.com/worthwhile/django-herald).\n\nThe `v0.3.0` release of Django-Herald has the same features and is equal to Django-Heralder `v0.3.0`.\n\nAs of Django-Heralder `v0.4.0`, Django-Heralder has diverged from original project with new features and bug fixes.\n\n## Installation\n\n### Supported Django / Python Versions\n\nWe try to make Heralder support all versions of django that django supports + all versions in between. \n\nFor python, Heralder supports all versions of python that the above versions of django support.\n\nAs of Heralder v0.4.0, we support:\n\n| Django | Python `3.9` | Python `3.10` | Python `3.11` | Python `3.12` | Python `3.13` |\n| --- | --- | --- | --- | --- | --- |\n| `3.2.x` | **Y** | **Y** | - | - | - |\n| `4.2.x` | **Y** | **Y** | **Y** | **Y** | - |\n| `5.2.x` | - | **Y** | **Y** | **Y** | **Y** |\n\n### Installation\n\n1. Install Django-Heralder using your favority packagement management tool (e.g. `pip`, `uv`, etc.)\n\n ```bash\n pip install django-heralder\n ```\n\n2. In your `settings.py` file, add `herald` and `django.contrib.sites` to `INSTALLED_APPS`:\n\n ```python\n # ... other settings ...\n\n INSTALLED_APPS = [\n # ... other apps ...\n 'herald',\n 'django.contrib.sites',\n ] \n ```\n\n3. In your main project `urls.py` file, add Heralder's URL routes:\n\n ```python\n from django.conf import settings\n from django.conf.urls import url, include\n\n urlpatterns = []\n\n if settings.DEBUG:\n urlpatterns = [\n url(r'^herald/', include('herald.urls')),\n ] + urlpatterns\n ```\n\n## Example Usage\n\n1. Create a `notifications.py` file in any django app. This is where your notification classes will live. Add a class like this:\n\n ```python\n from herald import registry\n from herald.base import EmailNotification\n\n\n class WelcomeEmail(EmailNotification): # extend from EmailNotification for emails\n template_name = 'welcome_email' # name of template, without extension\n subject = 'Welcome' # subject of email\n\n def __init__(self, user): # optionally customize the initialization\n self.context = {'user': user} # set context for the template rendering\n self.to_emails = [user.email] # set list of emails to send to\n\n @staticmethod\n def get_demo_args(): # define a static method to return list of args needed to initialize class for testing\n from users.models import User\n return [User.objects.order_by('?')[0]]\n\n registry.register(WelcomeEmail) # finally, register your notification class\n\n # Alternatively, a class decorator can be used to register the notification:\n\n @registry.register_decorator()\n class WelcomeEmail(EmailNotification):\n # ... more code ...\n ```\n\n2. Create templates for rendering the email using this file structure:\n\n ```text\n templates/\n herald/\n text/\n welcome_email.txt\n html/\n welcome_email.html\n ```\n\n3. Test how your email looks by navigating to `/herald/`.\n\n4. Additionally, preview your email before you send:\n\n ```python\n WelcomeEmail().preview(render_type=\"html\")\n ```\n\n5. Send your email wherever you need in your code:\n\n ```python\n WelcomeEmail(user).send()\n ```\n\n6. View the sent emails in django admin and even be able to resend it.\n\n## Setting template names\n\nThere's three different ways to specify `templatename`:\n\n1. A string without any slash, e.g. `\"welcome_email\"` and Herald will expect your file structure to be:\n\n ```text\n templates/\n herald/\n text/\n welcome_email.txt\n html/\n welcome_email.html\n ```\n\n2. A string with slashes, e.g. `\"path/to/welcome_email\"` and Herald will expect your file structure to be:\n\n ```text\n templates/\n path/\n to/\n welcome_email.txt\n welcome_email.html\n ```\n\n3. A dictionary with `text` and/or `html` keys with the path to the templates:\n\n ```python\n {\n \"text\": \"path/to/welcome_email_t.txt\",\n \"html\": \"path/to/welcome_email_h.html\",\n }\n ```\n\n and Herald will expect your file structure to be:\n\n ```text\n templates/\n path/\n to/\n welcome_email_t.txt\n welcome_email_h.html\n ```\n\n## Email options\n\nThe following options can be set on the email notification class. For Example:\n\n```python\nclass WelcomeEmail(EmailNotification):\n cc = ['test@example.com']\n```\n\n- `from_email`: (`str`, default: `settings.DEFAULT_FROM_EMAIL`) email address of sender\n- `subject`: (`str`, default: ) email subject\n- `to_emails`: (`List[str]`, default: `None`) list of email strings to send to\n- `bcc`: (`List[str]`, default: `None`) list of email strings to send as bcc\n- `cc`: (`List[str]`, default: `None`) list of email strings to send as cc\n- `headers`: (`dict`, default: `None`) extra headers to be passed along to the `EmailMultiAlternatives` object\n- `reply_to`: (`List[str]`, default: `None`) list of email strings to send as the Reply-To emails\n- `attachments`: (`list`) list of attachments. See \"Email Attachments\" below for more info\n\n## Automatically Deleting Old Notifications\n\nHerald can automatically delete old notifications whenever a new notification is sent.\n\nTo enable this, set the `HERALD_NOTIFICATION_RETENTION_TIME` setting to a timedelta instance.\n\nFor example:\n\n```python\nHERALD_NOTIFICATION_RETENTION_TIME = timedelta(weeks=8)\n```\n\nWill delete all notifications older than 8 weeks every time a new notification is sent.\n\n## Manually Deleting Old Notifications\n\nThe `delnotifs` command is useful for purging the notification history.\n\nThe default usage will delete everything from sent during today:\n\n```bash\npython manage.py delnotifs\n```\n\nHowever, you can also pass arguments for `start` or `end` dates. `end` is up to, but not including that date.\n- if only `end` is specified, delete anything sent before the end date.\n- if only `start` is specified, delete anything sent since the start date.\n- if both `start` and `end` are specified, delete anything sent in between, not including the end date.\n\n```bash\npython manage.py delnotifs --start='2016-01-01' --end='2016-01-10'\n```\n\n## Asynchronous Email Sending\n\nIf you are sending slightly different emails to a large number of people, it might take quite a while to process. By default, Django will process this all synchronously. For asynchronous support, we recommend django-celery-email. It is very straightfoward to setup and integrate: https://github.com/pmclanahan/django-celery-email\n\n## Custom SentNotification Model\n\nTo create a custom `SentNotification` model, inherit `SentNotificationAbstract`. From there you can add fields and methods as desired. To use this model through Heralder, set `HERALD_SENT_NOTIFICATION_MODEL` in your `settings.py` to the `app.ModelName` path. Then use `get_sent_notification_model` in `herald.utils` to retrieve the model.\n\nNote that using a custom model should be implemented as early as possible, ideally at the beginning of the project. Otherwise data may be split between the default table and the newly created custom table. To mitigate this, data will have to either be dropped or migrated to the new table. \n\nExample:\n\n```python\nfrom herald.models import SentNotificationAbstract\n\nclass SentNotificationCompany(SentNotificationAbstract):\n company_name = models.CharField(max_length=32)\n \n class Meta(SentNotificationAbstract.Meta):\n abstract = False\n```\n\nIn `settings.py`:\n\n```python\nHERALD_SENT_NOTIFICATION_MODEL = \"mpapp.SentNotificationCompany\"\n```\n\nUsing throughout your app:\n\n```python\nfrom herald.utils import get_sent_notification_model\n\nSentNotification = get_sent_notification_model()\n```\n\n## herald.contrib.auth\n\nDjango has built-in support for sending password reset emails. If you would like to send those emails using herald, you can use the notification class in herald.contrib.auth.\n\nFirst, add `herald.contrib.auth` to `INSTALLED_APPS` (in addition to `herald`).\n\nSecond, use the `HeraldPasswordResetForm` in place of django's built in `PasswordResetForm`. This step is entirely dependant on your project structure, but it essentially just involves changing the form class on the password reset view in some way:\n\n```python\n# you may simply just need to override the password reset url like so:\nurl(r'^password_reset/$', password_reset, name='password_reset', {'password_reset_form': HeraldPasswordResetForm}),\n\n# of if you are using something like django-authtools:\nurl(r'^password_reset/$', PasswordResetView.as_view(form_class=HeraldPasswordResetForm), name='password_reset'),\n\n# or you may have a customized version of the password reset view:\nclass MyPasswordResetView(FormView):\n form_class = HeraldPasswordResetForm # change the form class here\n\n# or, you may have a custom password reset form already. In that case, you will want to extend from the HeraldPasswordResetForm:\nclass MyPasswordResetForm(HeraldPasswordResetForm):\n ...\n\n# alternatively, you could even just send the notification wherever you wish, seperate from the form:\nPasswordResetEmail(some_user).send()\n```\n\nThird, you may want to customize the templates for the email. By default, herald will use the `registration/password_reset_email.html` that is provided by django for both the html and text versions of the email. But you can simply override `herald/html/password_reset.html` and/or `herald/text/password_reset.txt` to suit your needs.\n\n## User Disabled Notifications\n\nIf you want to disable certain notifications per user, add a record to the UserNotification table and\nadd notifications to the disabled_notifications many to many table.\n\nFor example:\n\n```python\nuser = User.objects.get(id=user.id)\n\nnotification = Notification.objects.get(notification_class=MyNotification.get_class_path())\n\n# disable the notification\nuser.usernotification.disabled_notifications.add(notification)\n```\n\nBy default, notifications can be disabled. You can put can_disable = False in your notification class and the system will populate the database with this default. Your Notification class can also override the verbose_name by setting it in your inherited Notification class. Like this:\n\n```python\nclass MyNotification(EmailNotification):\n can_disable = False\n verbose_name = \"My Required Notification\"\n```\n\n## Email Attachments\n\nTo send attachments, assign a list of attachments to the attachments attribute of your EmailNotification instance, or override the get_attachments() method.\n\nEach attachment in the list can be one of the following:\n\n1. A tuple which consists of the filename, the raw attachment data, and the mimetype. It is up to you to get the attachment data. Like this:\n\n ```python\n raw_data = get_pdf_data()\n\n email.attachments = [\n ('Report.pdf', raw_data, 'application/pdf'),\n ('report.txt', 'text version of report', 'text/plain')\n ]\n email.send()\n ```\n\n2. A MIMEBase object. See the documentation for attachments under EmailMessage Objects/attachments in the Django documentation.\n\n3. A django `File` object.\n\n### Inline Attachments\n\nSometimes you want to embed an image directly into the email content. Do that by using a MIMEImage assigning a content id header to a MIMEImage, like this:\n\n```python\nemail = WelcomeEmail(user)\nim = get_thumbnail(image_file.name, '600x600', quality=95)\nmy_image = MIMEImage(im.read()) # MIMEImage inherits from MIMEBase\nmy_image.add_header('Content-ID', '<{}>'.format(image_file.name))\n```\n\nYou can refer to these images in your html email templates using the Content ID (cid) like this:\n\n```html\n<img src=\"cid:{{image_file.name}}\" />\n```\n\nYou would of course need to add the \"image_file\" to your template context in the example above. You can also accomplish this using file operations. In this example we overrode the get_attachments method of an EmailNotification.\n\n```python\nclass MyNotification(EmailNotification):\n context = {'hello': 'world'}\n template_name = 'welcome_email'\n to_emails = ['somebody@example.com']\n subject = \"My email test\"\n \n def get_attachments(self):\n fp = open('python.jpeg', 'rb')\n img = MIMEImage(fp.read())\n img.add_header('Content-ID', '<{}>'.format('python.jpeg'))\n return [\n img,\n ]\n```\n\nAnd in your template you would refer to it like this, and you would not need to add anything to the context:\n\n```html\n<img src=\"cid:python.jpeg\" />\n```\n\n### Missing Templates\n\nBy default, Heralder will raise an exception if a template is missing when true (default).\n\n```python\nHERALD_RAISE_MISSING_TEMPLATES = True\n```\n\nIf you do not want this behavior, set this setting to False.\n\n```python\nHERALD_RAISE_MISSING_TEMPLATES = False\n```\n\n### HTML2Text Support\n\nDjango Herald can auto convert your HTML emails to plain text when installed with `hmtl2text` optional package. Any email without a plain text version will be auto converted if you enable this feature.\n\n1. Install Heralder with `html2text` support:\n\n ```bash\n pip install django-heralder[html2text]\n ```\n\n2. Follow the regular installation instructions.\n\n3. In your `settings.py` file, add this configuration setting to enable the `html2text` feature:\n\n ```python\n HERALD_HTML2TEXT_ENABLED = True\n ```\n\n4. You can customize the output of HTML2Text by setting a configuration dictionary. See [HTML2Text Configuration](https://github.com/Alir3z4/html2text/blob/master/docs/usage.md) for options:\n\n ```python\n HERALD_HTML2TEXT_CONFIG = {\n # Key / value configuration of html2text \n 'ignore_images': True # Ignores images in conversion\n }\n ```\n\n### Twilio\n\nHeralder supports Twilio as a notification provider when the optional package is installed.\n\n1. Install Heralder with `twilio` support:\n\n ```bash\n pip install django-heralder[twilio]\n ```\n\n2. Follow the regular installation instructions.\n\n3. In your `settings.py` file, set your Twilio account SID, token, and default \"from number\". You can retrieve these values on [Twilio Console](https://twilio.com/console). Security best practices recommend to NOT hard coding your SID or token in your source code. The example below:\n\n ```python\n # Twilio configurations\n # values taken from `twilio console`\n TWILIO_ACCOUNT_SID = \"your_account_sid\"\n TWILIO_AUTH_TOKEN = \"your_auth_token\"\n TWILIO_DEFAULT_FROM_NUMBER = \"+1234567890\"\n ```\n\nFor reference, Twilio has some great tutorials for Python: [Twilio Python Tutorial](https://www.twilio.com/docs/sms/quickstart/python)\n\n### Other MIME attachments\n\nYou can also attach any MIMEBase objects as regular attachments, but you must add a content-disposition header, or they will be inaccessible: \n\n```python\nmy_image.add_header('Content-Disposition', 'attachment; filename=\"python.jpg\"')\n```\n\nAttachments can cause your database to become quite large, so you should be sure to run the management commands to purge the database of old messages.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Django library for separating the message content from transmission method",
"version": "0.4.1",
"project_urls": {
"Download": "https://github.com/peterfarrell/django-heralder/tarball/0.4.1",
"Homepage": "https://github.com/peterfarrell/django-heralder/"
},
"split_keywords": [
"django",
" notifications",
" messaging"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "d267beb45c4cbca10e28c3d700c4baadd9fa060cf1b06e6bd1ee693d5899c637",
"md5": "dbbcc5d1fa1c63406082bcfd0c3152ea",
"sha256": "82189fdd04a72d9bd2192a418c391256b16b84876ee236fe1e41479801efc555"
},
"downloads": -1,
"filename": "django_heralder-0.4.1-py2.py3-none-any.whl",
"has_sig": false,
"md5_digest": "dbbcc5d1fa1c63406082bcfd0c3152ea",
"packagetype": "bdist_wheel",
"python_version": "py2.py3",
"requires_python": null,
"size": 25718,
"upload_time": "2025-08-21T20:32:51",
"upload_time_iso_8601": "2025-08-21T20:32:51.524398Z",
"url": "https://files.pythonhosted.org/packages/d2/67/beb45c4cbca10e28c3d700c4baadd9fa060cf1b06e6bd1ee693d5899c637/django_heralder-0.4.1-py2.py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "a52b2015fc133ac822bbf0dd428cadaa77ce6653be968109d6a357e4f4ae4f1f",
"md5": "15d24900e3cf38a2da9e42dc6fe2474b",
"sha256": "178b8857a9d7f3708e48a5f4bb5086c6b82ce9b1f3f4170e3247f5915759dad0"
},
"downloads": -1,
"filename": "django_heralder-0.4.1.tar.gz",
"has_sig": false,
"md5_digest": "15d24900e3cf38a2da9e42dc6fe2474b",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 26342,
"upload_time": "2025-08-21T20:32:52",
"upload_time_iso_8601": "2025-08-21T20:32:52.957778Z",
"url": "https://files.pythonhosted.org/packages/a5/2b/2015fc133ac822bbf0dd428cadaa77ce6653be968109d6a357e4f4ae4f1f/django_heralder-0.4.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-21 20:32:52",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "peterfarrell",
"github_project": "django-heralder",
"travis_ci": false,
"coveralls": true,
"github_actions": true,
"requirements": [
{
"name": "mock",
"specs": []
},
{
"name": "jsonpickle",
"specs": []
},
{
"name": "twilio",
"specs": []
},
{
"name": "coveralls",
"specs": []
},
{
"name": "pytz",
"specs": []
},
{
"name": "html2text",
"specs": []
}
],
"lcname": "django-heralder"
}