1#!/usr/bin/env python2 2 3# Copyright 2011 Google Inc. All Rights Reserved. 4"""Utilities to send email either through SMTP or SendGMR.""" 5 6from __future__ import print_function 7 8from email import encoders as Encoders 9from email.mime.base import MIMEBase 10from email.mime.multipart import MIMEMultipart 11from email.mime.text import MIMEText 12import os 13import smtplib 14import tempfile 15 16from cros_utils import command_executer 17 18 19class EmailSender(object): 20 """Utility class to send email through SMTP or SendGMR.""" 21 22 class Attachment(object): 23 """Small class to keep track of attachment info.""" 24 25 def __init__(self, name, content): 26 self.name = name 27 self.content = content 28 29 def SendEmail(self, 30 email_to, 31 subject, 32 text_to_send, 33 email_cc=None, 34 email_bcc=None, 35 email_from=None, 36 msg_type='plain', 37 attachments=None): 38 """Choose appropriate email method and call it.""" 39 if os.path.exists('/usr/bin/sendgmr'): 40 self.SendGMREmail(email_to, subject, text_to_send, email_cc, email_bcc, 41 email_from, msg_type, attachments) 42 else: 43 self.SendSMTPEmail(email_to, subject, text_to_send, email_cc, email_bcc, 44 email_from, msg_type, attachments) 45 46 def SendSMTPEmail(self, email_to, subject, text_to_send, email_cc, email_bcc, 47 email_from, msg_type, attachments): 48 """Send email via standard smtp mail.""" 49 # Email summary to the current user. 50 msg = MIMEMultipart() 51 52 if not email_from: 53 email_from = os.path.basename(__file__) 54 55 msg['To'] = ','.join(email_to) 56 msg['Subject'] = subject 57 58 if email_from: 59 msg['From'] = email_from 60 if email_cc: 61 msg['CC'] = ','.join(email_cc) 62 email_to += email_cc 63 if email_bcc: 64 msg['BCC'] = ','.join(email_bcc) 65 email_to += email_bcc 66 67 msg.attach(MIMEText(text_to_send, msg_type)) 68 if attachments: 69 for attachment in attachments: 70 part = MIMEBase('application', 'octet-stream') 71 part.set_payload(attachment.content) 72 Encoders.encode_base64(part) 73 part.add_header('Content-Disposition', 74 "attachment; filename=\"%s\"" % attachment.name) 75 msg.attach(part) 76 77 # Send the message via our own SMTP server, but don't include the 78 # envelope header. 79 s = smtplib.SMTP('localhost') 80 s.sendmail(email_from, email_to, msg.as_string()) 81 s.quit() 82 83 def SendGMREmail(self, email_to, subject, text_to_send, email_cc, email_bcc, 84 email_from, msg_type, attachments): 85 """Send email via sendgmr program.""" 86 ce = command_executer.GetCommandExecuter(log_level='none') 87 88 if not email_from: 89 email_from = os.path.basename(__file__) 90 91 to_list = ','.join(email_to) 92 93 if not text_to_send: 94 text_to_send = 'Empty message body.' 95 body_fd, body_filename = tempfile.mkstemp() 96 to_be_deleted = [body_filename] 97 98 try: 99 os.write(body_fd, text_to_send) 100 os.close(body_fd) 101 102 # Fix single-quotes inside the subject. In bash, to escape a single quote 103 # (e.g 'don't') you need to replace it with '\'' (e.g. 'don'\''t'). To 104 # make Python read the backslash as a backslash rather than an escape 105 # character, you need to double it. So... 106 subject = subject.replace("'", "'\\''") 107 108 if msg_type == 'html': 109 command = ("sendgmr --to='%s' --subject='%s' --html_file='%s' " 110 '--body_file=/dev/null' % (to_list, subject, body_filename)) 111 else: 112 command = ("sendgmr --to='%s' --subject='%s' --body_file='%s'" % 113 (to_list, subject, body_filename)) 114 if email_from: 115 command += ' --from=%s' % email_from 116 if email_cc: 117 cc_list = ','.join(email_cc) 118 command += " --cc='%s'" % cc_list 119 if email_bcc: 120 bcc_list = ','.join(email_bcc) 121 command += " --bcc='%s'" % bcc_list 122 123 if attachments: 124 attachment_files = [] 125 for attachment in attachments: 126 if '<html>' in attachment.content: 127 report_suffix = '_report.html' 128 else: 129 report_suffix = '_report.txt' 130 fd, fname = tempfile.mkstemp(suffix=report_suffix) 131 os.write(fd, attachment.content) 132 os.close(fd) 133 attachment_files.append(fname) 134 files = ','.join(attachment_files) 135 command += " --attachment_files='%s'" % files 136 to_be_deleted += attachment_files 137 138 # Send the message via our own GMR server. 139 status = ce.RunCommand(command) 140 return status 141 142 finally: 143 for f in to_be_deleted: 144 os.remove(f) 145