def build_email(self, email_from, email_to, subject, body, email_cc=None, email_bcc=None, reply_to=False, attachments=None, message_id=None, references=None, object_id=False, subtype='plain', headers=None, body_alternative=None, subtype_alternative='plain'): """Constructs an RFC2822 email.message.Message object based on the keyword arguments passed, and returns it. :param string email_from: sender email address :param list email_to: list of recipient addresses (to be joined with commas) :param string subject: email subject (no pre-encoding/quoting necessary) :param string body: email body, of the type ``subtype`` (by default, plaintext). If html subtype is used, the message will be automatically converted to plaintext and wrapped in multipart/alternative, unless an explicit ``body_alternative`` version is passed. :param string body_alternative: optional alternative body, of the type specified in ``subtype_alternative`` :param string reply_to: optional value of Reply-To header :param string object_id: optional tracking identifier, to be included in the message-id for recognizing replies. Suggested format for object-id is "res_id-model", e.g. "12345-crm.lead". :param string subtype: optional mime subtype for the text body (usually 'plain' or 'html'), must match the format of the ``body`` parameter. Default is 'plain', making the content part of the mail "text/plain". :param string subtype_alternative: optional mime subtype of ``body_alternative`` (usually 'plain' or 'html'). Default is 'plain'. :param list attachments: list of (filename, filecontents) pairs, where filecontents is a string containing the bytes of the attachment :param list email_cc: optional list of string values for CC header (to be joined with commas) :param list email_bcc: optional list of string values for BCC header (to be joined with commas) :param dict headers: optional map of headers to set on the outgoing mail (may override the other headers, including Subject, Reply-To, Message-Id, etc.) :rtype: email.message.Message (usually MIMEMultipart) :return: the new RFC2822 email message """ email_from = email_from or tools.config.get('email_from') assert email_from, "You must either provide a sender address explicitly or configure "\ "a global sender address in the server configuration or with the "\ "--email-from startup parameter." # Note: we must force all strings to to 8-bit utf-8 when crafting message, # or use encode_header() for headers, which does it automatically. headers = headers or {} # need valid dict later if not email_cc: email_cc = [] if not email_bcc: email_bcc = [] if not body: body = u'' email_body_utf8 = ustr(body).encode('utf-8') email_text_part = MIMEText(email_body_utf8, _subtype=subtype, _charset='utf-8') msg = MIMEMultipart() if not message_id: if object_id: message_id = tools.generate_tracking_message_id(object_id) else: message_id = make_msgid() msg['Message-Id'] = encode_header(message_id) if references: msg['references'] = encode_header(references) msg['Subject'] = encode_header(subject) msg['From'] = encode_rfc2822_address_header(email_from) del msg['Reply-To'] if reply_to: msg['Reply-To'] = encode_rfc2822_address_header(reply_to) else: msg['Reply-To'] = msg['From'] msg['To'] = encode_rfc2822_address_header(COMMASPACE.join(email_to)) if email_cc: msg['Cc'] = encode_rfc2822_address_header(COMMASPACE.join(email_cc)) if email_bcc: msg['Bcc'] = encode_rfc2822_address_header(COMMASPACE.join(email_bcc)) msg['Date'] = formatdate() # Custom headers may override normal headers or provide additional ones for key, value in headers.iteritems(): msg[ustr(key).encode('utf-8')] = encode_header(value) if subtype == 'html' and not body_alternative and html2text: # Always provide alternative text body ourselves if possible. text_utf8 = tools.html2text(email_body_utf8.decode('utf-8')).encode('utf-8') alternative_part = MIMEMultipart(_subtype="alternative") alternative_part.attach(MIMEText(text_utf8, _charset='utf-8', _subtype='plain')) alternative_part.attach(email_text_part) msg.attach(alternative_part) elif body_alternative: # Include both alternatives, as specified, within a multipart/alternative part alternative_part = MIMEMultipart(_subtype="alternative") body_alternative_utf8 = ustr(body_alternative).encode('utf-8') alternative_body_part = MIMEText(body_alternative_utf8, _subtype=subtype_alternative, _charset='utf-8') alternative_part.attach(alternative_body_part) alternative_part.attach(email_text_part) msg.attach(alternative_part) else: msg.attach(email_text_part) if attachments: for (fname, fcontent) in attachments: filename_rfc2047 = encode_header_param(fname) part = MIMEBase('application', "octet-stream") # The default RFC2231 encoding of Message.add_header() works in Thunderbird but not GMail # so we fix it by using RFC2047 encoding for the filename instead. part.set_param('name', filename_rfc2047) part.add_header('Content-Disposition', 'attachment', filename=filename_rfc2047) part.set_payload(fcontent) Encoders.encode_base64(part) msg.attach(part) return msg
def send_script_mail(self, cr, uid, ids=False, context=None ): date=datetime.strftime(datetime.now(),'%Y-%m-%d %H:%M:%S') date1=datetime.strftime(datetime.now(),'%Y-%m-%d 00:00:00') log_obj = self.pool.get('mail.logs') old_mail_ids = log_obj.search(cr,uid,[('state','=','outgoing'),('schedule_date','<',date1)]) if old_mail_ids: log_obj.write(cr, uid, old_mail_ids, {'state':'failed'}) mail_ids = log_obj.search(cr,uid,[('state','=','outgoing'),('schedule_date','<=',date),('schedule_date','>=',date1)]) for each in log_obj.browse(cr, uid, mail_ids): user = each.server_id.smtp_user password = each.server_id.smtp_pass attachments = [] for attach in each.data_ids: attachments.append((attach.datas_fname or attach.name, base64.b64decode(attach.datas), attach.inline, attach.cid)) strTo = each.email_to msgRoot = MIMEMultipart('related') msgRoot['Subject'] = each.subject msgRoot['From'] = user msgRoot['To'] = strTo msgRoot.preamble = 'This is a multi-part message in MIME format.' # Encapsulate the plain and HTML versions of the message body in an # 'alternative' part, so message agents can decide which they want to display. msgAlternative = MIMEMultipart('alternative') msgRoot.attach(msgAlternative) if not each.mail_body: each.mail_body='' if each.sign: signature= '-- \n'+ '\n' + each.sign else: signature='' SRC='' SRC3='' if attachments: for (fname, fcontent, inline, cid) in attachments: if inline: cid = fname.replace(" ", "_").lower() SRC = SRC + '<br><img src="cid:%s" ><br>' % cid SRC3= each.mail_body + SRC + signature print "SRC.................................",SRC3 msgText = MIMEText(SRC3,'html') msgAlternative.attach(msgText) if attachments: SRC='' for (fname, fcontent, inline, cid) in attachments: print "fname....***,",fname,"inline....***,",inline if inline: print "under if condition ........................",fname cid = fname.replace(" ", "_").lower() SRC = '<br><img src="cid:%s"><br>' % cid msgText = MIMEText(SRC, 'html') print "SRC.........",SRC msgImage = MIMEImage(fcontent) msgImage.add_header('Content-ID', '<%s>' % cid) msgImage.add_header('Content-Disposition' , 'inline' , filename=fname) msgRoot.attach(msgImage) else: print "under else condition ........................ when no inline",fname filename_rfc2047 = fname part = MIMEBase('application', "octet-stream") part.set_param('name', filename_rfc2047) part.add_header('Content-Disposition', 'attachment', filename=filename_rfc2047) part.set_payload(fcontent) Encoders.encode_base64(part) msgRoot.attach(part) try: print "message text............",msgText import smtplib smtp = smtplib.SMTP() smtp.connect('smtp.gmail.com',587) smtp.ehlo() smtp.starttls() smtp.login(user,password) smtp.sendmail(user, strTo, msgRoot.as_string()) smtp.quit() log_obj.write(cr,uid,[each.id],{'state':'sent'}) print "##################### EMAIL SENT SUCCESSFULLY #################" except: pass return True