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