Coverage for chalicelib/utils/email_handler.py: 76%

72 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-10-10 12:56 +0000

1import logging 

2import re 

3from email.header import Header 

4from email.mime.image import MIMEImage 

5from email.mime.multipart import MIMEMultipart 

6from email.mime.text import MIMEText 

7 

8from decouple import config 

9 

10from chalicelib.utils import smtp 

11 

12logger = logging.getLogger(__name__) 

13 

14 

15def __get_html_from_file(source, formatting_variables): 

16 if formatting_variables is None: 16 ↛ 17line 16 didn't jump to line 17 because the condition on line 16 was never true

17 formatting_variables = {} 

18 formatting_variables["frontend_url"] = config("SITE_URL") 

19 with open(source, "r") as body: 

20 BODY_HTML = body.read() 

21 if formatting_variables is not None and len(formatting_variables.keys()) > 0: 21 ↛ 24line 21 didn't jump to line 24

22 BODY_HTML = re.sub(r"%(?![(])", "%%", BODY_HTML) 

23 BODY_HTML = BODY_HTML % {**formatting_variables} 

24 return BODY_HTML 

25 

26 

27def __replace_images(HTML): 

28 pattern_holder = re.compile(r'<img[\w\W\n]+?(src="[a-zA-Z0-9.+\/\\-]+")') 

29 pattern_src = re.compile(r'src="(.*?)"') 

30 mime_img = [] 

31 swap = [] 

32 for m in re.finditer(pattern_holder, HTML): 

33 sub = m.groups()[0] 

34 sub = str(re.findall(pattern_src, sub)[0]) 

35 if sub not in swap: 35 ↛ 32line 35 didn't jump to line 32 because the condition on line 35 was always true

36 swap.append(sub) 

37 cid = f"img-{len(mime_img)}" 

38 HTML = HTML.replace(sub, f"cid:{cid}") 

39 sub = "chalicelib/utils/html/" + sub 

40 with open(sub, "rb") as image_file: 

41 img_data = image_file.read() 

42 mime_img.append(MIMEImage(img_data)) 

43 mime_img[-1].add_header('Content-ID', f'<{cid}>') 

44 return HTML, mime_img 

45 

46 

47def send_html(BODY_HTML, SUBJECT, recipient): 

48 BODY_HTML, mime_img = __replace_images(BODY_HTML) 

49 if not isinstance(recipient, list): 49 ↛ 51line 49 didn't jump to line 51 because the condition on line 49 was always true

50 recipient = [recipient] 

51 msg = MIMEMultipart('related') 

52 msg['Subject'] = Header(SUBJECT, 'utf-8') 

53 msg['From'] = config("EMAIL_FROM") 

54 

55 body = MIMEText(BODY_HTML, 'html', "utf-8") 

56 msg.attach(body) 

57 for m in mime_img: 

58 msg.attach(m) 

59 

60 with smtp.SMTPClient() as s: 

61 for r in recipient: 

62 msg["To"] = r 

63 try: 

64 logger.info(f"Email sending to: {r}") 

65 s.send_message(msg) 

66 except Exception as e: 

67 logger.error("!!! Email error!") 

68 logger.error(e) 

69 

70 

71def send_text(recipients, text, subject): 

72 with smtp.SMTPClient() as s: 

73 msg = MIMEMultipart() 

74 msg['Subject'] = Header(subject, 'utf-8') 

75 msg['From'] = config("EMAIL_FROM") 

76 msg['To'] = ", ".join(recipients) 

77 body = MIMEText(text) 

78 msg.attach(body) 

79 try: 

80 s.send_message(msg) 

81 except Exception as e: 

82 logger.error("!! Text-email failed: " + subject), 

83 logger.error(e) 

84 

85 

86def __escape_text_html(text): 

87 return text.replace("@", "<span>@</span>").replace(".", "<span>.</span>").replace("=", "<span>=</span>")