在 Django 或 Python 中发送带有日历 ICS 附件的文本 + HTML 电子邮件
Sending a text + HTML email with a calendar ICS attachment in Django or Python
我一直在寻找一个库或至少功能代码片段,让我从 Django(或至少在 Python)发送一封包含文本内容的电子邮件,HTML内容,以及每个主要电子邮件客户端都能识别的 ICS 日历附件。对于我的特定用例,如果向用户提供 'add to calendar' 按钮就足够了。
我觉得现在这应该是一个已解决的问题,但我只是找到了涉及未维护或过时或以其他方式不完整的库的答案。我已经测试了几个将附加 ICS 文件的片段,但 G-mail 没有像往常一样给我将其添加到日历的选项。
是否有我缺少的现成解决方案?
Django 内置了基于 python 的 smtplib 的解决方案:
https://docs.djangoproject.com/en/3.2/topics/email/
您需要在设置中为您的 smtp 服务器(gmail、mailgun 等)提供一些凭据,然后您可以使用 django.core.mail 模块。
要附加内容,您可以使用 EmailMessage.attach() 或 attach_file()
https://docs.djangoproject.com/en/3.2/topics/email/#django.core.mail.EmailMessage
首先创建一个 .ics 文件,这当然也可以通过 python 脚本来生成动态 .ics 文件。
.ics 文件
有关 iCalendar 的更多信息:基本信息和通用模板(参见下面的示例)。
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
UID:uid1@example.com
DTSTAMP:19970714T170000Z
ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
SUMMARY:Bastille Day Party
GEO:48.85299;2.36885
END:VEVENT
END:VCALENDAR
您也可以 generate 自己的 iCalendar,如果您觉得这样更容易的话(请参阅下面生成的示例)。
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//ical.marudot.com//iCal Event Maker
CALSCALE:GREGORIAN
BEGIN:VTIMEZONE
TZID:Europe/Berlin
LAST-MODIFIED:20201011T015911Z
TZURL:http://tzurl.org/zoneinfo-outlook/Europe/Berlin
X-LIC-LOCATION:Europe/Berlin
BEGIN:DAYLIGHT
TZNAME:CEST
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
BEGIN:STANDARD
TZNAME:CET
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTAMP:20210716T221958Z
UID:20210716T221958Z-901688629@marudot.com
DTSTART;TZID=Europe/Berlin:20210717T120000
DTEND;TZID=Europe/Berlin:20210717T160000
SUMMARY:Stack Overflow
DESCRIPTION:iCalendar example for Stack Overflow user Ciske\n
LOCATION:Amsterdam
BEGIN:VALARM
ACTION:DISPLAY
DESCRIPTION:Stack Overflow
TRIGGER:-PT1H
END:VALARM
END:VEVENT
END:VCALENDAR
Django settings.py
EMAIL_HOST = SMTP server.
EMAIL_HOST_USER = Login credentials for the SMTP server.
EMAIL_HOST_PASSWORD = Password credential for the SMTP server.
EMAIL_PORT = SMTP server port.
EMAIL_USE_TLS or _SSL = True if secure connection.
Django views.py
发送带有 .ics 文件作为附件的电子邮件。
from django.core.mail import EmailMessage
# Send email with attachment
email = EmailMessage(
'Subject',
'Email body',
'from@example.com',
['to@example.com']
)
email.attach_file('assets/invite.ics', 'text/calendar')
email.send()
您甚至可以将 .html 文件添加到您的电子邮件中。
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
html_content = render_to_string('assets/email.html', context)
email = EmailMultiAlternatives('Subject', 'Email body', 'from@example.com', [to@example.com])
email.attach_alternative(html_content, 'text/html')
email.attach_file('assets/invite.ics', 'text/calendar')
email.send()
您可以尝试使用 mark_safe()
它将 js,html 代码作为字符串呈现到 html 页面。
我用它来定制 Django 管理。
检查下面的例子:
some_sample_string = '''<h1>This is some sample </h1>'''
my_sample_html = mark_safe(some_sample_string)
您可以在 HTML 中设计一个页面,向其添加一些自定义设计,然后 return 将 mark_safe 字节对象添加到 HTML 或任何网页并对其进行标记在那里它将起作用。
您可以查看这些链接,它可能对您有所帮助
https://www.kite.com/python/docs/django.utils.safestring.mark_safe
Return mark_safe string from __str__
https://www.fullstackpython.com/django-utils-safestring-mark-safe-examples.html
https://docs.djangoproject.com/en/3.0/_modules/django/utils/html/
所以关键是将 ICS 文件附加为文件,而不是字符串(使用 django.core.mail.message.EmailMessage.attach_alternative()
)。
以下代码片段适用于我在 Gmail、Hotmail 和 Yahoo mail(待确认的 MS Outlook)中,这意味着日历事件信息与电子邮件一起显示,至少 Gmail 和 Hotmail 提供了添加选项将活动添加到您的日历。
from django.core.mail.message import EmailMultiAlternatives # At the top of your .py file
email = EmailMultiAlternatives(subject, message, settings.FROM_EMAIL, ['recipient@email.here'])
# email.attach_alternative('<b>html here</b>', 'text/html') # Optional HTML message
email.attach_file(filename_event, 'text/calendar')
email.send(fail_silently=False)
我正在使用 ics
https://pypi.org/project/ics/ to create the ICS file. This package is currently still being maintained. The only other major Python ics file library I could find is ical
https://pypi.org/project/icalendar/,并且截至 2021 年 9 月 1 日,该源已经有一年没有更新了。
此代码适用于我创建 ics 文件:
from ics import Calendar, Event # At the top of your .py file
ICS_DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
calendar = Calendar()
event = Event()
event.name = _("Our event name")
event.begin = appointment.start_time.strftime(ICS_DATETIME_FORMAT)
event.end = appointment.end_time.strftime(ICS_DATETIME_FORMAT)
event.organizer = settings.DEFAULT_FROM_EMAIL
calendar.events.add(event)
filename_event = 'invite-%d.ics' % appointment.id
with open(filename_event, 'w') as ics_file:
ics_file.writelines(calendar)
其中约会是我自己的Djangoclass,其中start_time和end_time是DateTimeField类型
如果您为每个请求创建一个新的 ics 文件,每个请求也有一个唯一的文件名很重要,这样您就不会冒两个单独的请求同时写入该文件的风险。
发送 ICS 文件后,我将删除它:
import os # At the top of your .py file
os.remove(filename_event)
我一直在寻找一个库或至少功能代码片段,让我从 Django(或至少在 Python)发送一封包含文本内容的电子邮件,HTML内容,以及每个主要电子邮件客户端都能识别的 ICS 日历附件。对于我的特定用例,如果向用户提供 'add to calendar' 按钮就足够了。
我觉得现在这应该是一个已解决的问题,但我只是找到了涉及未维护或过时或以其他方式不完整的库的答案。我已经测试了几个将附加 ICS 文件的片段,但 G-mail 没有像往常一样给我将其添加到日历的选项。
是否有我缺少的现成解决方案?
Django 内置了基于 python 的 smtplib 的解决方案:
https://docs.djangoproject.com/en/3.2/topics/email/
您需要在设置中为您的 smtp 服务器(gmail、mailgun 等)提供一些凭据,然后您可以使用 django.core.mail 模块。
要附加内容,您可以使用 EmailMessage.attach() 或 attach_file()
https://docs.djangoproject.com/en/3.2/topics/email/#django.core.mail.EmailMessage
首先创建一个 .ics 文件,这当然也可以通过 python 脚本来生成动态 .ics 文件。
.ics 文件
有关 iCalendar 的更多信息:基本信息和通用模板(参见下面的示例)。
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
UID:uid1@example.com
DTSTAMP:19970714T170000Z
ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
SUMMARY:Bastille Day Party
GEO:48.85299;2.36885
END:VEVENT
END:VCALENDAR
您也可以 generate 自己的 iCalendar,如果您觉得这样更容易的话(请参阅下面生成的示例)。
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//ical.marudot.com//iCal Event Maker
CALSCALE:GREGORIAN
BEGIN:VTIMEZONE
TZID:Europe/Berlin
LAST-MODIFIED:20201011T015911Z
TZURL:http://tzurl.org/zoneinfo-outlook/Europe/Berlin
X-LIC-LOCATION:Europe/Berlin
BEGIN:DAYLIGHT
TZNAME:CEST
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
BEGIN:STANDARD
TZNAME:CET
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTAMP:20210716T221958Z
UID:20210716T221958Z-901688629@marudot.com
DTSTART;TZID=Europe/Berlin:20210717T120000
DTEND;TZID=Europe/Berlin:20210717T160000
SUMMARY:Stack Overflow
DESCRIPTION:iCalendar example for Stack Overflow user Ciske\n
LOCATION:Amsterdam
BEGIN:VALARM
ACTION:DISPLAY
DESCRIPTION:Stack Overflow
TRIGGER:-PT1H
END:VALARM
END:VEVENT
END:VCALENDAR
Django settings.py
EMAIL_HOST = SMTP server.
EMAIL_HOST_USER = Login credentials for the SMTP server.
EMAIL_HOST_PASSWORD = Password credential for the SMTP server.
EMAIL_PORT = SMTP server port.
EMAIL_USE_TLS or _SSL = True if secure connection.
Django views.py
发送带有 .ics 文件作为附件的电子邮件。
from django.core.mail import EmailMessage
# Send email with attachment
email = EmailMessage(
'Subject',
'Email body',
'from@example.com',
['to@example.com']
)
email.attach_file('assets/invite.ics', 'text/calendar')
email.send()
您甚至可以将 .html 文件添加到您的电子邮件中。
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
html_content = render_to_string('assets/email.html', context)
email = EmailMultiAlternatives('Subject', 'Email body', 'from@example.com', [to@example.com])
email.attach_alternative(html_content, 'text/html')
email.attach_file('assets/invite.ics', 'text/calendar')
email.send()
您可以尝试使用 mark_safe()
它将 js,html 代码作为字符串呈现到 html 页面。
我用它来定制 Django 管理。
检查下面的例子:
some_sample_string = '''<h1>This is some sample </h1>'''
my_sample_html = mark_safe(some_sample_string)
您可以在 HTML 中设计一个页面,向其添加一些自定义设计,然后 return 将 mark_safe 字节对象添加到 HTML 或任何网页并对其进行标记在那里它将起作用。
您可以查看这些链接,它可能对您有所帮助
https://www.kite.com/python/docs/django.utils.safestring.mark_safe
Return mark_safe string from __str__
https://www.fullstackpython.com/django-utils-safestring-mark-safe-examples.html
https://docs.djangoproject.com/en/3.0/_modules/django/utils/html/
所以关键是将 ICS 文件附加为文件,而不是字符串(使用 django.core.mail.message.EmailMessage.attach_alternative()
)。
以下代码片段适用于我在 Gmail、Hotmail 和 Yahoo mail(待确认的 MS Outlook)中,这意味着日历事件信息与电子邮件一起显示,至少 Gmail 和 Hotmail 提供了添加选项将活动添加到您的日历。
from django.core.mail.message import EmailMultiAlternatives # At the top of your .py file
email = EmailMultiAlternatives(subject, message, settings.FROM_EMAIL, ['recipient@email.here'])
# email.attach_alternative('<b>html here</b>', 'text/html') # Optional HTML message
email.attach_file(filename_event, 'text/calendar')
email.send(fail_silently=False)
我正在使用 ics
https://pypi.org/project/ics/ to create the ICS file. This package is currently still being maintained. The only other major Python ics file library I could find is ical
https://pypi.org/project/icalendar/,并且截至 2021 年 9 月 1 日,该源已经有一年没有更新了。
此代码适用于我创建 ics 文件:
from ics import Calendar, Event # At the top of your .py file
ICS_DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
calendar = Calendar()
event = Event()
event.name = _("Our event name")
event.begin = appointment.start_time.strftime(ICS_DATETIME_FORMAT)
event.end = appointment.end_time.strftime(ICS_DATETIME_FORMAT)
event.organizer = settings.DEFAULT_FROM_EMAIL
calendar.events.add(event)
filename_event = 'invite-%d.ics' % appointment.id
with open(filename_event, 'w') as ics_file:
ics_file.writelines(calendar)
其中约会是我自己的Djangoclass,其中start_time和end_time是DateTimeField类型
如果您为每个请求创建一个新的 ics 文件,每个请求也有一个唯一的文件名很重要,这样您就不会冒两个单独的请求同时写入该文件的风险。
发送 ICS 文件后,我将删除它:
import os # At the top of your .py file
os.remove(filename_event)