~camptocamp/openobject-server/trunk-geoengine

« back to all changes in this revision

Viewing changes to openerp/tools/misc.py

  • Committer: nicolas.bessi at camptocamp
  • Date: 2011-09-14 07:44:08 UTC
  • mfrom: (3575.1.14 openobject-server)
  • Revision ID: nicolas.bessi@camptocamp.com-20110914074408-6578sltkjnvksnix
[MRG] from trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
45
45
from email.MIMEMultipart import MIMEMultipart
46
46
from email.Header import Header
47
47
from email.Utils import formatdate, COMMASPACE
 
48
from email import Utils
48
49
from email import Encoders
49
50
from itertools import islice, izip
50
51
from lxml import etree
59
60
    html2text = None
60
61
 
61
62
import openerp.loglevels as loglevels
 
63
import openerp.pooler as pooler
62
64
from config import config
63
65
from cache import *
64
66
 
280
282
    """, re.VERBOSE)
281
283
res_re = re.compile(r"\[([0-9]+)\]", re.UNICODE)
282
284
command_re = re.compile("^Set-([a-z]+) *: *(.+)$", re.I + re.UNICODE)
283
 
reference_re = re.compile("<.*-openobject-(\\d+)@(.*)>", re.UNICODE)
284
 
 
285
 
priorities = {
286
 
        '1': '1 (Highest)',
287
 
        '2': '2 (High)',
288
 
        '3': '3 (Normal)',
289
 
        '4': '4 (Low)',
290
 
        '5': '5 (Lowest)',
291
 
    }
 
285
reference_re = re.compile("<.*-open(?:object|erp)-(\\d+).*@(.*)>", re.UNICODE)
292
286
 
293
287
def html2plaintext(html, body_id=None, encoding='utf-8'):
294
288
    """ From an HTML text, convert the HTML to plain text.
354
348
 
355
349
    return html
356
350
 
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
359
353
    
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.
362
356
    """
363
 
    return "<%s-openobject-%s@%s>" % (time.time(), openobject_id, socket.gethostname())
364
 
 
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.
367
 
    
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)
375
 
    """
376
 
    class WriteToLogger(object):
377
 
        def __init__(self):
378
 
            self.logger = loglevels.Logger()
379
 
 
380
 
        def write(self, s):
381
 
            self.logger.notifyChannel('email_send', loglevels.LOG_DEBUG, s)
382
 
 
383
 
    if openobject_id:
384
 
        message['Message-Id'] = generate_tracking_message_id(openobject_id)
385
 
 
386
 
    try:
387
 
        smtp_server = config['smtp_server']
388
 
 
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))
394
 
            return True
395
 
 
396
 
        oldstderr = smtplib.stderr
397
 
        if not ssl: ssl = config.get('smtp_ssl', False)
398
 
        s = smtplib.SMTP()
399
 
        try:
400
 
            # in case of debug, the messages are printed to stderr.
401
 
            if debug:
402
 
                smtplib.stderr = WriteToLogger()
403
 
 
404
 
            s.set_debuglevel(int(bool(debug)))  # 0 or 1
405
 
            s.connect(smtp_server, config['smtp_port'])
406
 
            if ssl:
407
 
                s.ehlo()
408
 
                s.starttls()
409
 
                s.ehlo()
410
 
 
411
 
            if config['smtp_user'] or config['smtp_password']:
412
 
                s.login(config['smtp_user'], config['smtp_password'])
413
 
 
414
 
            s.sendmail(smtp_from, smtp_to_list, message.as_string())
415
 
        finally:
416
 
            try:
417
 
                s.quit()
418
 
                if debug:
419
 
                    smtplib.stderr = oldstderr
420
 
            except Exception:
421
 
                # ignored, just a consequence of the previous exception
422
 
                pass
423
 
 
424
 
    except Exception:
425
 
        _logger.error('could not deliver email', exc_info=True)
426
 
        return False
427
 
 
428
 
    return True
429
 
 
 
357
    return "<%s-openerp-%s@%s>" % (time.time(), res_id, socket.gethostname())
430
358
 
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'):
433
 
 
434
 
    """Send an email.
435
 
 
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
439
 
 
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).
 
363
 
 
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.
441
369
    """
442
 
    if x_headers is None:
443
 
        x_headers = {}
444
 
 
445
 
        
446
 
 
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")
450
 
 
451
 
    if not email_from: email_from = config.get('email_from', False)
452
 
    email_from = ustr(email_from).encode('utf-8')
453
 
 
454
 
    if not email_cc: email_cc = []
455
 
    if not email_bcc: email_bcc = []
456
 
    if not body: body = u''
457
 
 
458
 
    email_body = ustr(body).encode('utf-8')
459
 
    email_text = MIMEText(email_body or '',_subtype=subtype,_charset='utf-8')
460
 
 
461
 
    msg = MIMEMultipart()
462
 
 
463
 
    msg['Subject'] = Header(ustr(subject), 'utf-8')
464
 
    msg['From'] = email_from
465
 
    del msg['Reply-To']
466
 
    if reply_to:
467
 
        msg['Reply-To'] = reply_to
468
 
    else:
469
 
        msg['Reply-To'] = msg['From']
470
 
    msg['To'] = COMMASPACE.join(email_to)
471
 
    if email_cc:
472
 
        msg['Cc'] = COMMASPACE.join(email_cc)
473
 
    if email_bcc:
474
 
        msg['Bcc'] = COMMASPACE.join(email_bcc)
475
 
    msg['Date'] = formatdate(localtime=True)
476
 
 
477
 
    msg['X-Priority'] = priorities.get(priority, '3 (Normal)')
478
 
 
479
 
    # Add dynamic X Header
480
 
    for key, value in x_headers.iteritems():
481
 
        msg['%s' % key] = str(value)
482
 
 
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)
489
 
    else:
490
 
        msg.attach(email_text)
491
 
 
492
 
    if attach:
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,))
498
 
            msg.attach(part)
499
 
 
500
 
    return _email_send(email_from, flatten([email_to, email_cc, email_bcc]), msg, openobject_id=openobject_id, ssl=ssl, debug=debug)
 
370
 
 
371
    # If not cr, get cr from current thread database
 
372
    if not cr:
 
373
        db_name = getattr(threading.currentThread(), 'dbname', None)
 
374
        if db_name:
 
375
            cr = pooler.get_db_only(db_name).cursor()
 
376
        else:
 
377
            raise Exception("No database cursor found, please pass one explicitly")
 
378
 
 
379
    # Send Email
 
380
    try:
 
381
        mail_server_pool = pooler.get_pool(cr.dbname).get('ir.mail_server')
 
382
        res = False
 
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)
 
386
 
 
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)
 
390
    except Exception:
 
391
        _log.exception("tools.email_send failed to deliver email")
 
392
        return False
 
393
    finally:
 
394
        cr.close()
 
395
    return res
501
396
 
502
397
#----------------------------------------------------------
503
398
# SMS