357
def generate_tracking_message_id(openobject_id):
351
def generate_tracking_message_id(res_id):
358
352
"""Returns a string that can be used in the Message-ID RFC822 header field
360
354
Used to track the replies related to a given object thanks to the "In-Reply-To"
361
355
or "References" fields that Mail User Agents will set.
363
return "<%s-openobject-%s@%s>" % (time.time(), openobject_id, socket.gethostname())
365
def _email_send(smtp_from, smtp_to_list, message, openobject_id=None, ssl=False, debug=False):
366
""" Low-level method to send directly a Message through the configured smtp server.
368
:param smtp_from: RFC-822 envelope FROM (not displayed to recipient)
369
:param smtp_to_list: RFC-822 envelope RCPT_TOs (not displayed to recipient)
370
:param message: an email.message.Message to send
371
:param debug: True if messages should be output to stderr before being sent,
372
and smtplib.SMTP put into debug mode.
373
:return: True if the mail was delivered successfully to the smtp,
374
else False (+ exception logged)
376
class WriteToLogger(object):
378
self.logger = loglevels.Logger()
381
self.logger.notifyChannel('email_send', loglevels.LOG_DEBUG, s)
384
message['Message-Id'] = generate_tracking_message_id(openobject_id)
387
smtp_server = config['smtp_server']
389
if smtp_server.startswith('maildir:/'):
390
from mailbox import Maildir
391
maildir_path = smtp_server[8:]
392
mdir = Maildir(maildir_path,factory=None, create = True)
393
mdir.add(message.as_string(True))
396
oldstderr = smtplib.stderr
397
if not ssl: ssl = config.get('smtp_ssl', False)
400
# in case of debug, the messages are printed to stderr.
402
smtplib.stderr = WriteToLogger()
404
s.set_debuglevel(int(bool(debug))) # 0 or 1
405
s.connect(smtp_server, config['smtp_port'])
411
if config['smtp_user'] or config['smtp_password']:
412
s.login(config['smtp_user'], config['smtp_password'])
414
s.sendmail(smtp_from, smtp_to_list, message.as_string())
419
smtplib.stderr = oldstderr
421
# ignored, just a consequence of the previous exception
425
_logger.error('could not deliver email', exc_info=True)
357
return "<%s-openerp-%s@%s>" % (time.time(), res_id, socket.gethostname())
431
359
def email_send(email_from, email_to, subject, body, email_cc=None, email_bcc=None, reply_to=False,
432
attach=None, openobject_id=False, ssl=False, debug=False, subtype='plain', x_headers=None, priority='3'):
436
@param email_from A string used to fill the `From` header, if falsy,
437
config['email_from'] is used instead. Also used for
438
the `Reply-To` header if `reply_to` is not provided
440
@param email_to a sequence of addresses to send the mail to.
360
attachments=None, message_id=None, references=None, openobject_id=False, debug=False, subtype='plain', headers=None,
361
smtp_server=None, smtp_port=None, ssl=False, smtp_user=None, smtp_password=None, cr=None, uid=None):
362
"""Low-level function for sending an email (deprecated).
364
:deprecate: since OpenERP 6.1, please use ir.mail_server.send_email() instead.
365
:param email_from: A string used to fill the `From` header, if falsy,
366
config['email_from'] is used instead. Also used for
367
the `Reply-To` header if `reply_to` is not provided
368
:param email_to: a sequence of addresses to send the mail to.
442
if x_headers is None:
447
if not (email_from or config['email_from']):
448
raise ValueError("Sending an email requires either providing a sender "
449
"address or having configured one")
451
if not email_from: email_from = config.get('email_from', False)
452
email_from = ustr(email_from).encode('utf-8')
454
if not email_cc: email_cc = []
455
if not email_bcc: email_bcc = []
456
if not body: body = u''
458
email_body = ustr(body).encode('utf-8')
459
email_text = MIMEText(email_body or '',_subtype=subtype,_charset='utf-8')
461
msg = MIMEMultipart()
463
msg['Subject'] = Header(ustr(subject), 'utf-8')
464
msg['From'] = email_from
467
msg['Reply-To'] = reply_to
469
msg['Reply-To'] = msg['From']
470
msg['To'] = COMMASPACE.join(email_to)
472
msg['Cc'] = COMMASPACE.join(email_cc)
474
msg['Bcc'] = COMMASPACE.join(email_bcc)
475
msg['Date'] = formatdate(localtime=True)
477
msg['X-Priority'] = priorities.get(priority, '3 (Normal)')
479
# Add dynamic X Header
480
for key, value in x_headers.iteritems():
481
msg['%s' % key] = str(value)
483
if html2text and subtype == 'html':
484
text = html2text(email_body.decode('utf-8')).encode('utf-8')
485
alternative_part = MIMEMultipart(_subtype="alternative")
486
alternative_part.attach(MIMEText(text, _charset='utf-8', _subtype='plain'))
487
alternative_part.attach(email_text)
488
msg.attach(alternative_part)
490
msg.attach(email_text)
493
for (fname,fcontent) in attach:
494
part = MIMEBase('application', "octet-stream")
495
part.set_payload( fcontent )
496
Encoders.encode_base64(part)
497
part.add_header('Content-Disposition', 'attachment; filename="%s"' % (fname,))
500
return _email_send(email_from, flatten([email_to, email_cc, email_bcc]), msg, openobject_id=openobject_id, ssl=ssl, debug=debug)
371
# If not cr, get cr from current thread database
373
db_name = getattr(threading.currentThread(), 'dbname', None)
375
cr = pooler.get_db_only(db_name).cursor()
377
raise Exception("No database cursor found, please pass one explicitly")
381
mail_server_pool = pooler.get_pool(cr.dbname).get('ir.mail_server')
383
# Pack Message into MIME Object
384
email_msg = mail_server_pool.build_email(email_from, email_to, subject, body, email_cc, email_bcc, reply_to,
385
attachments, message_id, references, openobject_id, subtype, headers=headers)
387
res = mail_server_pool.send_email(cr, uid or 1, email_msg, mail_server_id=None,
388
smtp_server=smtp_server, smtp_port=smtp_port, smtp_user=smtp_user, smtp_password=smtp_password,
389
smtp_encryption=('ssl' if ssl else None), debug=debug)
391
_log.exception("tools.email_send failed to deliver email")
502
397
#----------------------------------------------------------