Belle II Software  release-08-01-10
mail_utils.py
1 
8 import os
9 import sys
10 import re
11 import subprocess
12 import random
13 import markdown
14 import smtplib
15 from string import Template
16 from email.mime.multipart import MIMEMultipart
17 from email.mime.text import MIMEText
18 from email.charset import add_charset, QP
19 
20 import validationpath
21 
22 
23 def get_greeting(name):
24  """
25  Get a random greeting and closing statement using name
26  """
27  greetings = [
28  "Dear",
29  "Dearest",
30  "Hi",
31  "Salutations",
32  "Hello",
33  "Exalted",
34  "Yo",
35  "Honorable",
36  "To the esteemed",
37  "Magnificent",
38  "Glorious",
39  "Howdy",
40  ]
41  closing = [
42  "Bye",
43  "Cheers",
44  "Best Regards",
45  "Best Wishes",
46  "Yours sincerely",
47  "Yours truly",
48  "Thank you",
49  "Seeya",
50  "Toodle-loo",
51  "Ciao",
52  "Hochachtungsvoll",
53  ]
54  return {
55  "greeting": "{} {}".format(random.choice(greetings), name),
56  "closing": random.choice(closing),
57  }
58 
59 
60 def markdown_to_plaintext(text):
61  """
62  removes markdown specific formatting elements from text
63  """
64  # replace all links of the form [text](url) by just the url.
65  replace_links = re.compile(r"\[.*?]\‍(([^)]*)\‍)")
66  text = replace_links.sub(r"\1", text)
67  # also replace all {: ... } braces which contain attribute lists
68  replace_attrs = re.compile(r"\{:([^\}\n]*?)\}")
69  text = replace_attrs.sub(r"", text)
70  # replace <http://link>, <https://link> and <me@mail.com> by removing <>
71  replace_autolink = re.compile(r"<(https?://[^>]*|[^> ]+@[^> ]+)>")
72  text = replace_autolink.sub(r"\1", text)
73  return text
74 
75 
76 def send_mail(
77  name, recipient, subject, text, link=None, link_title=None, mood="normal"
78 ):
79  """
80  Send an email to `name` at mail address `recipient` with the given subject and text.
81 
82  This function will add a greeting at the top and a closing statement at the
83  bottom and convert the mail text to html using markdown.
84 
85  The optional link/link_title argument can be used to easily add a link to
86  the mail for users to click.
87  """
88  all_moods = ["happy", "normal", "meh", "angry", "livid", "dead"]
89  if mood not in all_moods:
90  raise KeyError(
91  "Unknown mood please use one of {}".format(", ".join(all_moods))
92  )
93 
94  add_charset("utf-8", QP, QP, "utf-8")
95  msg = MIMEMultipart("alternative")
96  msg["Subject"] = subject
97  msg["From"] = "B2Bot <b2soft@mail.desy.de>"
98  if (
99  "bamboo_email_override" in os.environ
100  and os.environ["bamboo_email_override"].find("@") > 0
101  ):
102  msg["To"] = os.environ["bamboo_email_override"]
103  else:
104  msg["To"] = recipient
105 
106  if (
107  "bamboo_email_bcc" in os.environ
108  and os.environ["bamboo_email_bcc"].find("@") > 0
109  ):
110  msg["Bcc"] = os.environ["bamboo_email_bcc"]
111 
112  data = get_greeting(name)
113  data["mood"] = mood
114  data["title"] = subject
115  data["text"] = markdown_to_plaintext(text)
116  data["plain_link"] = ""
117  # Format the final goto link correctly if it is given
118  if link is not None:
119  if link_title is not None:
120  text += f"\n\n[{link_title}]({link}){{:.goto}}"
121  data["plain_link"] = f"\n\n{link_title}: {link}"
122  else:
123  text += f"\n\n<{link}>{{:.goto}}"
124  data["plain_link"] = f"\n\n{link}"
125 
126  # parse plain text to html
127  data["body"] = markdown.markdown(
128  text,
129  output_format="xhtml1",
130  extensions=["markdown.extensions.attr_list"],
131  )
132  # create multipart mime mail
133  msg.attach(
134  MIMEText(
135  "{greeting},\n\n{text}{plain_link}\n\n{closing}"
136  "\n\tThe Belle II Software Bot (B2Bot)".format(**data),
137  "plain",
138  )
139  )
140  template = Template(
141  open(
142  os.path.join(
143  validationpath.get_basepath()["local"],
144  "validation/html_static/templates/template_mail.html",
145  )
146  ).read()
147  )
148  msg.attach(MIMEText(template.substitute(**data), "html"))
149 
150  if os.environ.get("bamboo_DRYRUN", False):
151  # print("Send Mail: ", msg.as_bytes().decode(), file=sys.stderr)
152  open(msg["To"] + ".html", "w").write(template.substitute(**data))
153  else:
154  # check for a local mail_config.py and use it to send the mail if it
155  # exists, otherwise use /usr/sbin/sendmail
156  try:
157  from mail_config import sendmail
158 
159  try:
160  sendmail(msg)
161  except smtplib.SMTPAuthenticationError as e:
162  print(
163  "!!!!!!!!!!!!!!!!!!!!!\n"
164  "AN ERROR OCCURED DURING SENDING OF MAILS:",
165  file=sys.stderr,
166  )
167  print(e, file=sys.stderr)
168  print("!!!!!!!!!!!!!!!!!!!!!", file=sys.stderr)
169  except ImportError:
170  subprocess.run(
171  ["/usr/sbin/sendmail", "-t", "-oi"], input=msg.as_bytes()
172  )