forked from CGM_Public/pretix_original
MIMEEncode inline images as CID
This commit is contained in:
@@ -1,11 +1,16 @@
|
|||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
import smtplib
|
import smtplib
|
||||||
import warnings
|
import warnings
|
||||||
|
from email.encoders import encode_noop
|
||||||
|
from email.mime.image import MIMEImage
|
||||||
from email.utils import formataddr
|
from email.utils import formataddr
|
||||||
from typing import Any, Dict, List, Union
|
from typing import Any, Dict, List, Union
|
||||||
|
|
||||||
import cssutils
|
import cssutils
|
||||||
|
import requests
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
from celery import chain
|
from celery import chain
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.mail import EmailMultiAlternatives, get_connection
|
from django.core.mail import EmailMultiAlternatives, get_connection
|
||||||
@@ -13,6 +18,7 @@ from django.template.loader import get_template
|
|||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django_scopes import scope, scopes_disabled
|
from django_scopes import scope, scopes_disabled
|
||||||
from i18nfield.strings import LazyI18nString
|
from i18nfield.strings import LazyI18nString
|
||||||
|
from raven.utils import urlparse
|
||||||
|
|
||||||
from pretix.base.email import ClassicMailRenderer
|
from pretix.base.email import ClassicMailRenderer
|
||||||
from pretix.base.i18n import language
|
from pretix.base.i18n import language
|
||||||
@@ -220,7 +226,9 @@ def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: st
|
|||||||
invoices: List[int]=None, order: int=None, attach_tickets=False) -> bool:
|
invoices: List[int]=None, order: int=None, attach_tickets=False) -> bool:
|
||||||
email = EmailMultiAlternatives(subject, body, sender, to=to, bcc=bcc, headers=headers)
|
email = EmailMultiAlternatives(subject, body, sender, to=to, bcc=bcc, headers=headers)
|
||||||
if html is not None:
|
if html is not None:
|
||||||
email.attach_alternative(html, "text/html")
|
html_with_cid, cid_images = replace_images_with_cid_paths(html)
|
||||||
|
email = attach_cid_images(email, cid_images, verify_ssl=True)
|
||||||
|
email.attach_alternative(html_with_cid, "text/html")
|
||||||
|
|
||||||
if event:
|
if event:
|
||||||
with scopes_disabled():
|
with scopes_disabled():
|
||||||
@@ -332,3 +340,75 @@ def render_mail(template, context):
|
|||||||
tpl = get_template(template)
|
tpl = get_template(template)
|
||||||
body = tpl.render(context)
|
body = tpl.render(context)
|
||||||
return body
|
return body
|
||||||
|
|
||||||
|
|
||||||
|
def replace_images_with_cid_paths(body_html):
|
||||||
|
if body_html:
|
||||||
|
email = BeautifulSoup(body_html, "html5lib")
|
||||||
|
image_counter = 1
|
||||||
|
cid_images = []
|
||||||
|
for image in email.findAll('img'):
|
||||||
|
cid_id = "image_%s" % (image_counter)
|
||||||
|
image_counter = image_counter + 1
|
||||||
|
original_image_src = image['src']
|
||||||
|
|
||||||
|
image['src'] = "cid:%s" % (cid_id)
|
||||||
|
|
||||||
|
cid_images.append({
|
||||||
|
'src': original_image_src,
|
||||||
|
'cid_id': cid_id
|
||||||
|
})
|
||||||
|
|
||||||
|
return email.prettify(), cid_images
|
||||||
|
else:
|
||||||
|
return body_html, []
|
||||||
|
|
||||||
|
|
||||||
|
def attach_cid_images(msg, cid_images, verify_ssl=True):
|
||||||
|
if cid_images and len(cid_images) > 0:
|
||||||
|
|
||||||
|
msg.mixed_subtype = 'related'
|
||||||
|
for image in cid_images:
|
||||||
|
try:
|
||||||
|
mime_image = convert_image_to_cid(
|
||||||
|
image['src'], image['cid_id'], verify_ssl)
|
||||||
|
if mime_image:
|
||||||
|
msg.attach(mime_image)
|
||||||
|
except Exception as e:
|
||||||
|
print("ERROR attaching CID image %s[%s] %s" % (image['cid_id'], image['src'], str(e)))
|
||||||
|
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
def convert_image_to_cid(image_src, cid_id, verify_ssl=True):
|
||||||
|
try:
|
||||||
|
image_src_split = image_src.split('data:image/png;base64,')
|
||||||
|
if len(image_src_split) == 2:
|
||||||
|
mime_image = MIMEImage(image_src_split[1], _subtype="png", _encoder=encode_noop)
|
||||||
|
mime_image.add_header('Content-Transfer-Encoding', 'base64')
|
||||||
|
else:
|
||||||
|
image_src = normalize_image_url(image_src)
|
||||||
|
|
||||||
|
path = urlparse.urlparse(image_src).path
|
||||||
|
guess_subtype = os.path.splitext(path)[1][1:]
|
||||||
|
|
||||||
|
response = requests.get(image_src, verify=verify_ssl)
|
||||||
|
mime_image = MIMEImage(
|
||||||
|
response.content, _subtype=guess_subtype)
|
||||||
|
|
||||||
|
mime_image.add_header('Content-ID', '<%s>' % cid_id)
|
||||||
|
|
||||||
|
return mime_image
|
||||||
|
except Exception as e:
|
||||||
|
print("ERROR creating mime_image %s[%s] %s" % (cid_id, image_src, str(e)))
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_image_url(url):
|
||||||
|
if '//' not in url.lower():
|
||||||
|
if settings.STATIC_URL.startswith('http'):
|
||||||
|
url = "%s%s" % (settings.MEDIA_ROOT, url)
|
||||||
|
else:
|
||||||
|
url = "%s%s%s" % (settings.SITE_URL, settings.STATIC_URL, url)
|
||||||
|
|
||||||
|
return url
|
||||||
|
|||||||
Reference in New Issue
Block a user