def test_maildir(self): tmpdir = mkdtemp('archweb') mdir = tmpdir + '/maildir' maildir = Maildir(mdir) msg = Message() msg['subject'] = 'John Doe' msg['to'] = 'John Doe <*****@*****.**>' maildir.add(msg) # Invalid call_command('donor_import', mdir) self.assertEqual(len(Donor.objects.all()), 0) # Valid msg = Message() msg['subject'] = 'Receipt [$25.00] By: David Doe [[email protected]]' msg['to'] = 'John Doe <*****@*****.**>' maildir.add(msg) call_command('donor_import', mdir) self.assertEqual(len(Donor.objects.all()), 1) # Re-running should result in no new donor call_command('donor_import', mdir) self.assertEqual(len(Donor.objects.all()), 1) rmtree(tmpdir)
def send_email(self, message): """Sends an email directly (no queuing). No retries are done, the caller should handle MailDeliveryException in order to ensure that the mail is never lost. :param message: the email.message.Message to send. The envelope sender will be extracted from the ``Return-Path`` or ``From`` headers. The envelope recipients will be extracted from the combined list of ``To``, ``CC`` and ``BCC`` headers. :return: the Message-ID of the message that was just sent, if successfully sent, otherwise raises MailDeliveryException and logs root cause. """ smtp_from = message['Return-Path'] or message['From'] assert smtp_from, "The Return-Path or From header is required for any outbound email" # The email's "Envelope From" (Return-Path), and all recipient addresses must only contain ASCII characters. from_rfc2822 = extract_rfc2822_addresses(smtp_from) assert len( from_rfc2822 ) == 1, "Malformed 'Return-Path' or 'From' address - it may only contain plain ASCII characters" smtp_from = from_rfc2822[0] email_to = message['To'] email_cc = message['Cc'] email_bcc = message['Bcc'] smtp_to_list = filter( None, flatten( map(extract_rfc2822_addresses, [email_to, email_cc, email_bcc]))) assert smtp_to_list, "At least one valid recipient address should be specified for outgoing emails (To/Cc/Bcc)" try: message_id = message['Message-Id'] # Add email in Maildir if smtp_host contains maildir. if self.smtp_host.startswith('maildir:/'): from mailbox import Maildir maildir_path = self.smtp_host[8:] mdir = Maildir(maildir_path, factory=None, create=True) mdir.add(message.as_string(True)) return message_id try: self.conn.sendmail(smtp_from, smtp_to_list, message.as_string()) finally: try: # Close Connection of SMTP Server self.conn.quit() except Exception: # ignored, just a consequence of the previous exception pass except Exception, e: msg = "Mail delivery failed via SMTP server '%s'.\n%s: %s" % ( unicode(self.smtp_host), e.__class__.__name__, unicode(e)) raise ZatoException(self.cid, msg)
def _email_send(smtp_from, smtp_to_list, message, openobject_id=None, ssl=False, debug=False): """Low-level method to send directly a Message through the configured smtp server. :param smtp_from: RFC-822 envelope FROM (not displayed to recipient) :param smtp_to_list: RFC-822 envelope RCPT_TOs (not displayed to recipient) :param message: an email.message.Message to send :param debug: True if messages should be output to stderr before being sent, and smtplib.SMTP put into debug mode. :return: True if the mail was delivered successfully to the smtp, else False (+ exception logged) """ if openobject_id: message['Message-Id'] = "<%s-openobject-%s@%s>" % (time.time(), openobject_id, socket.gethostname()) try: smtp_server = config['smtp_server'] if smtp_server.startswith('maildir:/'): from mailbox import Maildir maildir_path = smtp_server[8:] mdir = Maildir(maildir_path,factory=None, create = True) mdir.add(msg.as_string(True)) return True oldstderr = smtplib.stderr if not ssl: ssl = config.get('smtp_ssl', False) s = smtplib.SMTP() try: # in case of debug, the messages are printed to stderr. if debug: smtplib.stderr = WriteToLogger() s.set_debuglevel(int(bool(debug))) # 0 or 1 s.connect(smtp_server, config['smtp_port']) if ssl: s.ehlo() s.starttls() s.ehlo() if config['smtp_user'] or config['smtp_password']: s.login(config['smtp_user'], config['smtp_password']) s.sendmail(smtp_from, smtp_to_list, message.as_string()) finally: try: s.quit() if debug: smtplib.stderr = oldstderr except: # ignored, just a consequence of the previous exception pass except Exception, e: _logger.error('could not deliver email', exc_info=True) return False
def main(args=sys.argv): parser = option_parser() opts, args = parser.parse_args(args) if len(args) > 1: if len(args) < 4: print ('You must specify the from address, to address and body text' ' on the command line') return 1 msg = compose_mail(args[1], args[2], args[3], subject=opts.subject, attachment=opts.attachment) from_, to = args[1:3] eto = [extract_email_address(x.strip()) for x in to.split(',')] efrom = extract_email_address(from_) else: msg = sys.stdin.read() from email import message_from_string from email.utils import getaddresses eml = message_from_string(msg) tos = eml.get_all('to', []) ccs = eml.get_all('cc', []) + eml.get_all('bcc', []) all_tos = [] for x in tos + ccs: all_tos.extend(y.strip() for y in x.split(',')) eto = list(map(extract_email_address, all_tos)) if not eto: raise ValueError('Email from STDIN does not specify any recipients') efrom = getaddresses(eml.get_all('from', [])) if not efrom: raise ValueError('Email from STDIN does not specify a sender') efrom = efrom[0][1] outbox = None if opts.outbox is not None: outbox = os.path.abspath(os.path.expanduser(opts.outbox)) from mailbox import Maildir outbox = Maildir(opts.outbox, factory=None) if opts.fork: if os.fork() != 0: return 0 try: sendmail(msg, efrom, eto, localhost=opts.localhost, verbose=opts.verbose, timeout=opts.timeout, relay=opts.relay, username=opts.username, password=opts.password, port=opts.port, encryption=opts.encryption_method) except: if outbox is not None: outbox.add(msg) outbox.close() print 'Delivery failed. Message saved to', opts.outbox raise return 0
def send_email(self, message): """Sends an email directly (no queuing). No retries are done, the caller should handle MailDeliveryException in order to ensure that the mail is never lost. :param message: the email.message.Message to send. The envelope sender will be extracted from the ``Return-Path`` or ``From`` headers. The envelope recipients will be extracted from the combined list of ``To``, ``CC`` and ``BCC`` headers. :return: the Message-ID of the message that was just sent, if successfully sent, otherwise raises MailDeliveryException and logs root cause. """ smtp_from = message['Return-Path'] or message['From'] assert smtp_from, "The Return-Path or From header is required for any outbound email" # The email's "Envelope From" (Return-Path), and all recipient addresses must only contain ASCII characters. from_rfc2822 = extract_rfc2822_addresses(smtp_from) assert len(from_rfc2822) == 1, "Malformed 'Return-Path' or 'From' address - it may only contain plain ASCII characters" smtp_from = from_rfc2822[0] email_to = message['To'] email_cc = message['Cc'] email_bcc = message['Bcc'] smtp_to_list = filter(None, flatten(map(extract_rfc2822_addresses,[email_to, email_cc, email_bcc]))) assert smtp_to_list, "At least one valid recipient address should be specified for outgoing emails (To/Cc/Bcc)" try: message_id = message['Message-Id'] # Add email in Maildir if smtp_host contains maildir. if self.smtp_host.startswith('maildir:/'): from mailbox import Maildir maildir_path = self.smtp_host[8:] mdir = Maildir(maildir_path, factory=None, create = True) mdir.add(message.as_string(True)) return message_id try: self.conn.sendmail(smtp_from, smtp_to_list, message.as_string()) finally: try: # Close Connection of SMTP Server self.conn.quit() except Exception: # ignored, just a consequence of the previous exception pass except Exception, e: msg = "Mail delivery failed via SMTP server '%s'.\n%s: %s" % (unicode(self.smtp_host), e.__class__.__name__, unicode(e)) raise ZatoException(self.cid, msg)
def archive_message(mlist, message): """See `IArchiver`. This archiver saves messages into a maildir. """ archive_dir = os.path.join(config.ARCHIVE_DIR, 'prototype') try: os.makedirs(archive_dir, 0o775) except OSError as error: # If this already exists, then we're fine if error.errno != errno.EEXIST: raise # Maildir will throw an error if the directories are partially created # (for instance the toplevel exists but cur, new, or tmp do not) # therefore we don't create the toplevel as we did above. list_dir = os.path.join(archive_dir, mlist.fqdn_listname) mailbox = Maildir(list_dir, create=True, factory=None) lock_file = os.path.join( config.LOCK_DIR, '{0}-maildir.lock'.format(mlist.fqdn_listname)) # Lock the maildir as Maildir.add() is not threadsafe. Don't use the # context manager because it's not an error if we can't acquire the # archiver lock. We'll just log the problem and continue. # # XXX 2012-03-14 BAW: When we extend the chain/pipeline architecture # to other runners, e.g. the archive runner, it would be better to let # any TimeOutError propagate up. That would cause the message to be # re-queued and tried again later, rather than being discarded as # happens now below. lock = Lock(lock_file) try: lock.lock(timeout=timedelta(seconds=1)) # Add the message to the maildir. The return value could be used # to construct the file path if necessary. E.g. # # os.path.join(archive_dir, mlist.fqdn_listname, 'new', # message_key) mailbox.add(message) except TimeOutError: # Log the error and go on. log.error('Unable to acquire prototype archiver lock for {0}, ' 'discarding: {1}'.format( mlist.fqdn_listname, message.get('message-id', 'n/a'))) finally: lock.unlock(unconditionally=True) # Can we get return the URL of the archived message? return None
def _maildir_delivery(self, username, domain, data): try: path = os.path.join(os.path.expanduser(MAILDIR_DELIVERY_USER), domain, username) mdir = Maildir(path) mdirid = mdir.add(data) print "Maildir Delivered %s@%s %s/%s" % (username, domain, path, mdirid) except: # XXX log errors with maildir but continue print "Maildir delivery error %s@%s " % (username, domain)
def populateMailbox(self, username): # Here will the mail directory of the user be stored pathShort = "/var/vmail/" + self.domain + "/" + username pathLong = pathShort + "/Maildir" # Create those directories os.mkdir(pathShort) mailbox = Maildir(pathLong) # And now populate that directory numOfMails = random.randint(1, 6666) percentageRead = random.randint(0, 100) for i in xrange(1, numOfMails): message = MaildirMessage(message=str(i)) message.set_subdir("cur") readSeed = random.randint(0, 100) if percentageRead <= readSeed: message.set_flags("S") mailbox.add(message) self.chmodMailbox(pathShort)
async def handle_DATA(self, server, session, envelope): d = Maildir(MAILDIR_PATH) message = email.message_from_bytes(envelope.original_content) for r in envelope.rcpt_tos: message['X-Rcpt-To'] = r d.add(message) try: conn = smtplib.SMTP(RELAY_HOST, RELAY_PORT) conn.ehlo() conn.starttls() conn.login(RELAY_USER, RELAY_PASS) refused = conn.sendmail(envelope.mail_from, envelope.rcpt_tos, envelope.original_content) if refused: print(refused, flush=True) print("To: %r" % (envelope.rcpt_tos, ), flush=True) return '250 OK' except smtplib.SMTPException as exn: traceback.print_exc() return '550 SMTPException: %s' % exn
def store_mail(tf, mail, maildir, metadata): """Store the given mail inside the maildir with its metadata""" # Retrieve the message msg = MaildirMessage(tf.extractfile(mail['name'])) msg.set_flags(get_msgflags(metadata[mail['name']])) folder = path.dirname(mail['name']) # Find the mailbox in which to store the mail md = None if re.match('Inbox(\![0-9]+)?$', folder): md = Maildir(maildir) elif re.match('Inbox/', folder): # Nested folders under Inbox, put them under a folder named # 'INBOX'. folder = folder.replace('/', '.').replace('Inbox', 'INBOX') md = Maildir(path.join(maildir, '.' + folder), factory=None) elif re.match('Sent(\ Items.*)?', folder): md = Maildir(path.join(maildir, '.' + 'Sent'), factory=None) else: md = Maildir(path.join(maildir, '.' + folder), factory=None) # Store the mail md.add(msg)
def send_email(self, cr, uid, message, mail_server_id=None, smtp_server=None, smtp_port=None, smtp_user=None, smtp_password=None, smtp_encryption=None, smtp_debug=False, context=None): _logger.warn('Mandriil custom was here %s' % str(message)) """Sends an email directly (no queuing). No retries are done, the caller should handle MailDeliveryException in order to ensure that the mail is never lost. If the mail_server_id is provided, sends using this mail server, ignoring other smtp_* arguments. If mail_server_id is None and smtp_server is None, use the default mail server (highest priority). If mail_server_id is None and smtp_server is not None, use the provided smtp_* arguments. If both mail_server_id and smtp_server are None, look for an 'smtp_server' value in server config, and fails if not found. :param message: the email.message.Message to send. The envelope sender will be extracted from the ``Return-Path`` or ``From`` headers. The envelope recipients will be extracted from the combined list of ``To``, ``CC`` and ``BCC`` headers. :param mail_server_id: optional id of ir.mail_server to use for sending. overrides other smtp_* arguments. :param smtp_server: optional hostname of SMTP server to use :param smtp_encryption: optional TLS mode, one of 'none', 'starttls' or 'ssl' (see ir.mail_server fields for explanation) :param smtp_port: optional SMTP port, if mail_server_id is not passed :param smtp_user: optional SMTP user, if mail_server_id is not passed :param smtp_password: optional SMTP password to use, if mail_server_id is not passed :param smtp_debug: optional SMTP debug flag, if mail_server_id is not passed :return: the Message-ID of the message that was just sent, if successfully sent, otherwise raises MailDeliveryException and logs root cause. """ smtp_from = message['Return-Path'] or message['From'] assert smtp_from, "The Return-Path or From header is required for any outbound email" # The email's "Envelope From" (Return-Path), and all recipient addresses must only contain ASCII characters. from_rfc2822 = extract_rfc2822_addresses(smtp_from) assert from_rfc2822, ("Malformed 'Return-Path' or 'From' address: %r - " "It should contain one valid plain ASCII email") % smtp_from # use last extracted email, to support rarities like 'Support@MyComp <*****@*****.**>' smtp_from = from_rfc2822[-1] email_to = message['To'] email_cc = message['Cc'] email_bcc = message['Bcc'] smtp_to_list = filter(None, tools.flatten(map(extract_rfc2822_addresses,[email_to, email_cc, email_bcc]))) assert smtp_to_list, self.NO_VALID_RECIPIENT x_forge_to = message['X-Forge-To'] if x_forge_to: # `To:` header forged, e.g. for posting on mail.groups, to avoid confusion del message['X-Forge-To'] del message['To'] # avoid multiple To: headers! message['To'] = x_forge_to # Do not actually send emails in testing mode! if getattr(threading.currentThread(), 'testing', False): _test_logger.info("skip sending email in test mode") return message['Message-Id'] # Get SMTP Server Details from Mail Server mail_server = None if mail_server_id: mail_server = self.browse(cr, SUPERUSER_ID, mail_server_id) elif not smtp_server: mail_server_ids = self.search(cr, SUPERUSER_ID, [], order='sequence', limit=1) if mail_server_ids: mail_server = self.browse(cr, SUPERUSER_ID, mail_server_ids[0]) if mail_server: smtp_server = mail_server.smtp_host smtp_user = mail_server.smtp_user smtp_password = mail_server.smtp_pass smtp_port = mail_server.smtp_port smtp_encryption = mail_server.smtp_encryption smtp_debug = smtp_debug or mail_server.smtp_debug else: # we were passed an explicit smtp_server or nothing at all smtp_server = smtp_server or tools.config.get('smtp_server') smtp_port = tools.config.get('smtp_port', 25) if smtp_port is None else smtp_port smtp_user = smtp_user or tools.config.get('smtp_user') smtp_password = smtp_password or tools.config.get('smtp_password') if smtp_encryption is None and tools.config.get('smtp_ssl'): smtp_encryption = 'starttls' # STARTTLS is the new meaning of the smtp_ssl flag as of v7.0 if not smtp_server: raise osv.except_osv( _("Missing SMTP Server"), _("Please define at least one SMTP server, or provide the SMTP parameters explicitly.")) message_id = message['Message-Id'] # Hook 1 if smtp_server=='mandrill': if tools.config.get('mandrill_key', False): return self.send_mandrill(cr, SUPERUSER_ID, message) else: _logger.warn('You set SMTP server as mandrill but not sent mandril API key in Odoo config file. Use standart Odoo core folow. Please set param mandrill_key in config file') # Hook 1 # Hook 2 if smtp_server=='smtp.mandrillapp.com': user_obj=self.pool['res.users'].browse(cr, SUPERUSER_ID, uid) normal_from=peplace_email(message['From'], user_obj.login) del message['From'] del message['Reply-To'] message['From']=normal_from message['Reply-To']=normal_from _logger.warn('smtp.mandrillapp.com message %s' % str(message)) # Hook 2 try: # Add email in Maildir if smtp_server contains maildir. if smtp_server.startswith('maildir:/'): from mailbox import Maildir maildir_path = smtp_server[8:] mdir = Maildir(maildir_path, factory=None, create = True) mdir.add(message.as_string(True)) return message_id smtp = None try: smtp = self.connect(smtp_server, smtp_port, smtp_user, smtp_password, smtp_encryption or False, smtp_debug) rez=smtp.sendmail(smtp_from, smtp_to_list, message.as_string()) _logger.warn('SMTP send Res %s' % str(rez)) finally: if smtp is not None: smtp.quit() except Exception, e: msg = _("Mail delivery failed via SMTP server '%s'.\n%s: %s") % (tools.ustr(smtp_server), e.__class__.__name__, tools.ustr(e)) _logger.error(msg) raise MailDeliveryException(_("Mail Delivery Failed"), msg)
def send_email(self, message, mail_server_id=None, smtp_server=None, smtp_port=None, smtp_user=None, smtp_password=None, smtp_encryption=None, smtp_debug=False): """Sends an email directly (no queuing). No retries are done, the caller should handle MailDeliveryException in order to ensure that the mail is never lost. If the mail_server_id is provided, sends using this mail server, ignoring other smtp_* arguments. If mail_server_id is None and smtp_server is None, use the default mail server (highest priority). If mail_server_id is None and smtp_server is not None, use the provided smtp_* arguments. If both mail_server_id and smtp_server are None, look for an 'smtp_server' value in server config, and fails if not found. :param message: the email.message.Message to send. The envelope sender will be extracted from the ``Return-Path`` (if present), or will be set to the default bounce address. The envelope recipients will be extracted from the combined list of ``To``, ``CC`` and ``BCC`` headers. :param mail_server_id: optional id of ir.mail_server to use for sending. overrides other smtp_* arguments. :param smtp_server: optional hostname of SMTP server to use :param smtp_encryption: optional TLS mode, one of 'none', 'starttls' or 'ssl' (see ir.mail_server fields for explanation) :param smtp_port: optional SMTP port, if mail_server_id is not passed :param smtp_user: optional SMTP user, if mail_server_id is not passed :param smtp_password: optional SMTP password to use, if mail_server_id is not passed :param smtp_debug: optional SMTP debug flag, if mail_server_id is not passed :return: the Message-ID of the message that was just sent, if successfully sent, otherwise raises MailDeliveryException and logs root cause. """ # Use the default bounce address **only if** no Return-Path was # provided by caller. Caller may be using Variable Envelope Return # Path (VERP) to detect no-longer valid email addresses. smtp_from = message['Return-Path'] or self._get_default_bounce_address( ) or message['From'] assert smtp_from, "The Return-Path or From header is required for any outbound email" # The email's "Envelope From" (Return-Path), and all recipient addresses must only contain ASCII characters. from_rfc2822 = extract_rfc2822_addresses(smtp_from) assert from_rfc2822, ( "Malformed 'Return-Path' or 'From' address: %r - " "It should contain one valid plain ASCII email") % smtp_from # use last extracted email, to support rarities like 'Support@MyComp <*****@*****.**>' smtp_from = from_rfc2822[-1] email_to = message['To'] email_cc = message['Cc'] email_bcc = message['Bcc'] smtp_to_list = filter( None, tools.flatten( map(extract_rfc2822_addresses, [email_to, email_cc, email_bcc]))) assert smtp_to_list, self.NO_VALID_RECIPIENT x_forge_to = message['X-Forge-To'] if x_forge_to: # `To:` header forged, e.g. for posting on mail.channels, to avoid confusion del message['X-Forge-To'] del message['To'] # avoid multiple To: headers! message['To'] = x_forge_to # Do not actually send emails in testing mode! if getattr(threading.currentThread(), 'testing', False): _test_logger.info("skip sending email in test mode") return message['Message-Id'] # Get SMTP Server Details from Mail Server mail_server = None if mail_server_id: mail_server = self.sudo().browse(mail_server_id) elif not smtp_server: mail_server = self.sudo().search([], order='sequence', limit=1) if mail_server: smtp_server = mail_server.smtp_host smtp_user = mail_server.smtp_user smtp_password = mail_server.smtp_pass smtp_port = mail_server.smtp_port smtp_encryption = mail_server.smtp_encryption smtp_debug = smtp_debug or mail_server.smtp_debug else: # we were passed an explicit smtp_server or nothing at all smtp_server = smtp_server or tools.config.get('smtp_server') smtp_port = tools.config.get( 'smtp_port', 25) if smtp_port is None else smtp_port smtp_user = smtp_user or tools.config.get('smtp_user') smtp_password = smtp_password or tools.config.get('smtp_password') if smtp_encryption is None and tools.config.get('smtp_ssl'): smtp_encryption = 'starttls' # STARTTLS is the new meaning of the smtp_ssl flag as of v7.0 if not smtp_server: raise UserError( _("Missing SMTP Server") + "\n" + _("Please define at least one SMTP server, or provide the SMTP parameters explicitly." )) #mod by Yuri message.replace_header('From', '%s <%s>' % (message['From'], smtp_user)) if message.has_key('return-path'): message.replace_header('return-path', '%s' % (smtp_user, )) else: message.add_header('return-path', '%s' % (smtp_user, )) try: message_id = message['Message-Id'] # Add email in Maildir if smtp_server contains maildir. if smtp_server.startswith('maildir:/'): from mailbox import Maildir maildir_path = smtp_server[8:] mdir = Maildir(maildir_path, factory=None, create=True) mdir.add(message.as_string(True)) return message_id smtp = None try: smtp = self.connect(smtp_server, smtp_port, smtp_user, smtp_password, smtp_encryption or False, smtp_debug) smtp.sendmail(smtp_user, smtp_to_list, message.as_string()) finally: if smtp is not None: smtp.quit() except Exception as e: params = (ustr(smtp_server), e.__class__.__name__, ustr(e)) msg = _( "Mail delivery failed via SMTP server '%s'.\n%s: %s") % params _logger.info(msg) raise MailDeliveryException(_("Mail Delivery Failed"), msg) return message_id
def send_email( self, cr, uid, message, mail_server_id=None, smtp_server=None, smtp_port=None, smtp_user=None, smtp_password=None, smtp_encryption=None, smtp_debug=False, context=None, ): """Sends an email directly (no queuing). No retries are done, the caller should handle MailDeliveryException in order to ensure that the mail is never lost. If the mail_server_id is provided, sends using this mail server, ignoring other smtp_* arguments. If mail_server_id is None and smtp_server is None, use the default mail server (highest priority). If mail_server_id is None and smtp_server is not None, use the provided smtp_* arguments. If both mail_server_id and smtp_server are None, look for an 'smtp_server' value in server config, and fails if not found. :param message: the email.message.Message to send. The envelope sender will be extracted from the ``Return-Path`` (if present), or will be set to the default bounce address. The envelope recipients will be extracted from the combined list of ``To``, ``CC`` and ``BCC`` headers. :param mail_server_id: optional id of ir.mail_server to use for sending. overrides other smtp_* arguments. :param smtp_server: optional hostname of SMTP server to use :param smtp_encryption: optional TLS mode, one of 'none', 'starttls' or 'ssl' (see ir.mail_server fields for explanation) :param smtp_port: optional SMTP port, if mail_server_id is not passed :param smtp_user: optional SMTP user, if mail_server_id is not passed :param smtp_password: optional SMTP password to use, if mail_server_id is not passed :param smtp_debug: optional SMTP debug flag, if mail_server_id is not passed :return: the Message-ID of the message that was just sent, if successfully sent, otherwise raises MailDeliveryException and logs root cause. """ # Use the default bounce address **only if** no Return-Path was # provided by caller. Caller may be using Variable Envelope Return # Path (VERP) to detect no-longer valid email addresses. smtp_from = message["Return-Path"] if not smtp_from: smtp_from = self._get_default_bounce_address(cr, uid, context=context) if not smtp_from: smtp_from = message["From"] assert smtp_from, "The Return-Path or From header is required for any outbound email" # The email's "Envelope From" (Return-Path), and all recipient addresses must only contain ASCII characters. from_rfc2822 = extract_rfc2822_addresses(smtp_from) assert from_rfc2822, ( "Malformed 'Return-Path' or 'From' address: %r - " "It should contain one valid plain ASCII email" ) % smtp_from # use last extracted email, to support rarities like 'Support@MyComp <*****@*****.**>' smtp_from = from_rfc2822[-1] email_to = message["To"] email_cc = message["Cc"] email_bcc = message["Bcc"] smtp_to_list = filter(None, tools.flatten(map(extract_rfc2822_addresses, [email_to, email_cc, email_bcc]))) assert smtp_to_list, self.NO_VALID_RECIPIENT x_forge_to = message["X-Forge-To"] if x_forge_to: # `To:` header forged, e.g. for posting on mail.groups, to avoid confusion del message["X-Forge-To"] del message["To"] # avoid multiple To: headers! message["To"] = x_forge_to # Do not actually send emails in testing mode! if getattr(threading.currentThread(), "testing", False): _test_logger.info("skip sending email in test mode") return message["Message-Id"] # Get SMTP Server Details from Mail Server mail_server = None if mail_server_id: mail_server = self.browse(cr, SUPERUSER_ID, mail_server_id) elif not smtp_server: mail_server_ids = self.search(cr, SUPERUSER_ID, [], order="sequence", limit=1) if mail_server_ids: mail_server = self.browse(cr, SUPERUSER_ID, mail_server_ids[0]) if mail_server: smtp_server = mail_server.smtp_host smtp_user = mail_server.smtp_user smtp_password = mail_server.smtp_pass smtp_port = mail_server.smtp_port smtp_encryption = mail_server.smtp_encryption smtp_debug = smtp_debug or mail_server.smtp_debug else: # we were passed an explicit smtp_server or nothing at all smtp_server = smtp_server or tools.config.get("smtp_server") smtp_port = tools.config.get("smtp_port", 25) if smtp_port is None else smtp_port smtp_user = smtp_user or tools.config.get("smtp_user") smtp_password = smtp_password or tools.config.get("smtp_password") if smtp_encryption is None and tools.config.get("smtp_ssl"): smtp_encryption = "starttls" # STARTTLS is the new meaning of the smtp_ssl flag as of v7.0 if not smtp_server: raise UserError( _("Missing SMTP Server") + "\n" + _("Please define at least one SMTP server, or provide the SMTP parameters explicitly.") ) try: message_id = message["Message-Id"] # Add email in Maildir if smtp_server contains maildir. if smtp_server.startswith("maildir:/"): from mailbox import Maildir maildir_path = smtp_server[8:] mdir = Maildir(maildir_path, factory=None, create=True) mdir.add(message.as_string(True)) return message_id smtp = None try: smtp = self.connect( smtp_server, smtp_port, smtp_user, smtp_password, smtp_encryption or False, smtp_debug ) smtp.sendmail(smtp_from, smtp_to_list, message.as_string()) finally: if smtp is not None: smtp.quit() except Exception, e: msg = _("Mail delivery failed via SMTP server '%s'.\n%s: %s") % ( tools.ustr(smtp_server), e.__class__.__name__, tools.ustr(e), ) _logger.info(msg) raise MailDeliveryException(_("Mail Delivery Failed"), msg)
def send_email(self, cr, uid, message, mail_server_id=None, smtp_server=None, smtp_port=None, smtp_user=None, smtp_password=None, smtp_encryption=None, smtp_debug=False, context=None): """Override the standard method to fix the issue of using a mail client where relaying is disallowed.""" # Use the default bounce address **only if** no Return-Path was # provided by caller. Caller may be using Variable Envelope Return # Path (VERP) to detect no-longer valid email addresses. smtp_from = message['Return-Path'] if not smtp_from: smtp_from = self._get_default_bounce_address(cr, uid, context=context) if not smtp_from: smtp_from = message['From'] assert smtp_from, ( "The Return-Path or From header is required for any outbound email" ) # The email's "Envelope From" (Return-Path), and all recipient # addresses must only contain ASCII characters. from_rfc2822 = extract_rfc2822_addresses(smtp_from) assert from_rfc2822, ( "Malformed 'Return-Path' or 'From' address: %r - " "It should contain one valid plain ASCII email") % smtp_from # use last extracted email, to support rarities like # 'Support@MyComp <*****@*****.**>' smtp_from = from_rfc2822[-1] email_to = message['To'] email_cc = message['Cc'] email_bcc = message['Bcc'] smtp_to_list = filter( None, tools.flatten( map(extract_rfc2822_addresses, [email_to, email_cc, email_bcc]))) assert smtp_to_list, self.NO_VALID_RECIPIENT x_forge_to = message['X-Forge-To'] if x_forge_to: # `To:` header forged, e.g. for posting on mail.groups, # to avoid confusion del message['X-Forge-To'] del message['To'] # avoid multiple To: headers! message['To'] = x_forge_to # Do not actually send emails in testing mode! if getattr(threading.currentThread(), 'testing', False): _test_logger.info("skip sending email in test mode") return message['Message-Id'] # Get SMTP Server Details from Mail Server mail_server = None if mail_server_id: mail_server = self.browse(cr, SUPERUSER_ID, mail_server_id) elif not smtp_server: mail_server_ids = self.search(cr, SUPERUSER_ID, [], order='sequence', limit=1) if mail_server_ids: mail_server = self.browse(cr, SUPERUSER_ID, mail_server_ids[0]) if mail_server: smtp_server = mail_server.smtp_host smtp_user = mail_server.smtp_user smtp_password = mail_server.smtp_pass smtp_port = mail_server.smtp_port smtp_encryption = mail_server.smtp_encryption smtp_debug = smtp_debug or mail_server.smtp_debug else: # we were passed an explicit smtp_server or nothing at all smtp_server = smtp_server or tools.config.get('smtp_server') smtp_port = tools.config.get( 'smtp_port', 25) if smtp_port is None else smtp_port smtp_user = smtp_user or tools.config.get('smtp_user') smtp_password = smtp_password or tools.config.get('smtp_password') if smtp_encryption is None and tools.config.get('smtp_ssl'): smtp_encryption = 'starttls' # STARTTLS is the new meaning of the smtp_ssl flag as of v7.0 if not smtp_server: raise osv.except_osv( _("Missing SMTP Server"), _("Please define at least one SMTP server, or " "provide the SMTP parameters explicitly.")) try: message_id = message['Message-Id'] # Add email in Maildir if smtp_server contains maildir. if smtp_server.startswith('maildir:/'): from mailbox import Maildir maildir_path = smtp_server[8:] mdir = Maildir(maildir_path, factory=None, create=True) mdir.add(message.as_string(True)) return message_id smtp = None try: # START OF CODE ADDED smtp = self.connect(smtp_server, smtp_port, smtp_user, smtp_password, smtp_encryption or False, smtp_debug) # smtp.sendmail(smtp_from, smtp_to_list, message.as_string()) from email.utils import parseaddr, formataddr # exact name and address (oldname, oldemail) = parseaddr(message['From']) # use original name with new address newfrom = formataddr((oldname, smtp_user)) # need to use replace_header instead '=' to prevent # double field message.replace_header('From', newfrom) smtp.sendmail(smtp_user, smtp_to_list, message.as_string()) # END OF CODE ADDED finally: if smtp is not None: smtp.quit() except Exception, e: msg = _("Mail delivery failed via SMTP server '%s'.\n%s: %s") % ( tools.ustr(smtp_server), e.__class__.__name__, tools.ustr(e)) _logger.error(msg) raise MailDeliveryException(_("Mail Delivery Failed"), msg)
def send_email( self, cr, uid, message, mail_server_id=None, smtp_server=None, smtp_port=None, smtp_user=None, smtp_password=None, smtp_encryption=None, smtp_debug=False, context=None, ): """Sends an email directly (no queuing). No retries are done, the caller should handle MailDeliveryException in order to ensure that the mail is never lost. If the mail_server_id is provided, sends using this mail server, ignoring other smtp_* arguments. If mail_server_id is None and smtp_server is None, use the default mail server (highest priority). If mail_server_id is None and smtp_server is not None, use the provided smtp_* arguments. If both mail_server_id and smtp_server are None, look for an 'smtp_server' value in server config, and fails if not found. :param message: the email.message.Message to send. The envelope sender will be extracted from the ``Return-Path`` or ``From`` headers. The envelope recipients will be extracted from the combined list of ``To``, ``CC`` and ``BCC`` headers. :param mail_server_id: optional id of ir.mail_server to use for sending. overrides other smtp_* arguments. :param smtp_server: optional hostname of SMTP server to use :param smtp_encryption: optional TLS mode, one of 'none', 'starttls' or 'ssl' (see ir.mail_server fields for explanation) :param smtp_port: optional SMTP port, if mail_server_id is not passed :param smtp_user: optional SMTP user, if mail_server_id is not passed :param smtp_password: optional SMTP password to use, if mail_server_id is not passed :param smtp_debug: optional SMTP debug flag, if mail_server_id is not passed :return: the Message-ID of the message that was just sent, if successfully sent, otherwise raises MailDeliveryException and logs root cause. """ smtp_from = message["Return-Path"] or message["From"] assert smtp_from, "The Return-Path or From header is required for any outbound email" # The email's "Envelope From" (Return-Path), and all recipient addresses must only contain ASCII characters. from_rfc2822 = extract_rfc2822_addresses(smtp_from) assert from_rfc2822, ( "Malformed 'Return-Path' or 'From' address: %r - " "It should contain one valid plain ASCII email" ) % smtp_from # use last extracted email, to support rarities like 'Support@MyComp <*****@*****.**>' smtp_from = from_rfc2822[-1] email_to = message["To"] email_cc = message["Cc"] email_bcc = message["Bcc"] smtp_to_list = filter(None, tools.flatten(map(extract_rfc2822_addresses, [email_to, email_cc, email_bcc]))) assert smtp_to_list, self.NO_VALID_RECIPIENT # Do not actually send emails in testing mode! if getattr(threading.currentThread(), "testing", False): _logger.log(logging.INFO, "skip sending email in test mode") return message["Message-Id"] # Get SMTP Server Details from Mail Server mail_server = None if mail_server_id: mail_server = self.browse(cr, SUPERUSER_ID, mail_server_id) elif not smtp_server: mail_server_ids = self.search(cr, SUPERUSER_ID, [], order="sequence", limit=1) if mail_server_ids: mail_server = self.browse(cr, SUPERUSER_ID, mail_server_ids[0]) if mail_server: smtp_server = mail_server.smtp_host smtp_user = mail_server.smtp_user smtp_password = mail_server.smtp_pass smtp_port = mail_server.smtp_port smtp_encryption = mail_server.smtp_encryption smtp_debug = smtp_debug or mail_server.smtp_debug else: # we were passed an explicit smtp_server or nothing at all smtp_server = smtp_server or tools.config.get("smtp_server") smtp_port = tools.config.get("smtp_port", 25) if smtp_port is None else smtp_port smtp_user = smtp_user or tools.config.get("smtp_user") smtp_password = smtp_password or tools.config.get("smtp_password") if smtp_encryption is None and tools.config.get("smtp_ssl"): smtp_encryption = "starttls" # STARTTLS is the new meaning of the smtp_ssl flag as of v7.0 if not smtp_server: raise osv.except_osv( _("Missing SMTP Server"), _("Please define at least one SMTP server, or provide the SMTP parameters explicitly."), ) try: message_id = message["Message-Id"] # Add email in Maildir if smtp_server contains maildir. if smtp_server.startswith("maildir:/"): from mailbox import Maildir maildir_path = smtp_server[8:] mdir = Maildir(maildir_path, factory=None, create=True) mdir.add(message.as_string(True)) return message_id try: smtp = self.connect(smtp_server, smtp_port, smtp_user, smtp_password, smtp_encryption or False, smtp_debug) # smtp.sendmail(smtp_from, smtp_to_list, message.as_string()) """ johnw 02/18/2014 enhance the mail sending logic to handle the "login and from address not mathcing" issue, for example, 163.com will raise exception under this case if from and login user is different, then to try to send using smtp_user again """ try: smtp.sendmail(smtp_from, smtp_to_list, message.as_string()) except Exception, e: if smtp_from != smtp_user: smtp.sendmail(smtp_user, smtp_to_list, message.as_string()) else: raise e finally: try: # Close Connection of SMTP Server smtp.quit() except Exception: # ignored, just a consequence of the previous exception pass except Exception, e: msg = _("Mail delivery failed via SMTP server '%s'.\n%s: %s") % ( tools.ustr(smtp_server), e.__class__.__name__, tools.ustr(e), ) _logger.exception(msg) raise MailDeliveryException(_("Mail delivery failed"), msg)
def send_email(self, message, mail_server_id=None, smtp_server=None, smtp_port=None, smtp_user=None, smtp_password=None, smtp_encryption=None, smtp_debug=False, context=None): from_rfc2822 = extract_rfc2822_addresses(message['From'])[-1] server_id = self.env['ir.mail_server'].search([ '|', ('id', '=', self.env.user.send_mail_server_id.id), ('id', '=', self.env.user.company_id.send_mail_server_id.id) ], order='sequence', limit=1) #.search( [('smtp_user', '=', from_rfc2822)],) if server_id and server_id[0]: message['Return-Path'] = from_rfc2822 smtp_from = message['Return-Path'] if not smtp_from: smtp_from = self._get_default_bounce_address(context=context) if not smtp_from: smtp_from = message['From'] assert smtp_from, "The Return-Path or From header is required for any outbound email" # The email's "Envelope From" (Return-Path), and all recipient addresses must only contain ASCII characters. from_rfc2822 = extract_rfc2822_addresses(smtp_from) assert from_rfc2822, ( "Malformed 'Return-Path' or 'From' address: %r - " "It should contain one valid plain ASCII email") % smtp_from # use last extracted email, to support rarities like 'Support@MyComp <*****@*****.**>' smtp_from = from_rfc2822[-1] email_to = message['To'] email_cc = message['Cc'] email_bcc = message['Bcc'] smtp_to_list = filter( None, tools.flatten( map(extract_rfc2822_addresses, [email_to, email_cc, email_bcc]))) assert smtp_to_list, self.NO_VALID_RECIPIENT x_forge_to = message['X-Forge-To'] if x_forge_to: # `To:` header forged, e.g. for posting on mail.groups, to avoid confusion del message['X-Forge-To'] del message['To'] # avoid multiple To: headers! message['To'] = x_forge_to # Do not actually send emails in testing mode! if getattr(threading.currentThread(), 'testing', False): _test_logger.info("skip sending email in test mode") return message['Message-Id'] # Get SMTP Server Details from Mail Server mail_server = None if mail_server_id: mail_server = self.browse(mail_server_id) elif not smtp_server: mail_server_ids = self.search([], order='sequence', limit=1) if mail_server_ids: mail_server = self.browse(mail_server_ids[0]) if mail_server: smtp_server = mail_server.smtp_host smtp_user = mail_server.smtp_user smtp_password = mail_server.smtp_pass smtp_port = mail_server.smtp_port smtp_encryption = mail_server.smtp_encryption smtp_debug = smtp_debug or mail_server.smtp_debug else: # we were passed an explicit smtp_server or nothing at all smtp_server = smtp_server or tools.config.get('smtp_server') smtp_port = tools.config.get( 'smtp_port', 25) if smtp_port is None else smtp_port smtp_user = smtp_user or tools.config.get('smtp_user') smtp_password = smtp_password or tools.config.get('smtp_password') if smtp_encryption is None and tools.config.get('smtp_ssl'): smtp_encryption = 'starttls' # STARTTLS is the new meaning of the smtp_ssl flag as of v7.0 if not smtp_server: raise osv.except_osv( _("Missing SMTP Server"), _("Please define at least one SMTP server, or provide the SMTP parameters explicitly." )) try: message_id = message['Message-Id'] # Add email in Maildir if smtp_server contains maildir. if smtp_server.startswith('maildir:/'): from mailbox import Maildir maildir_path = smtp_server[8:] mdir = Maildir(maildir_path, factory=None, create=True) mdir.add(message.as_string(True)) return message_id smtp = None try: smtp = self.connect(smtp_server, smtp_port, smtp_user, smtp_password, smtp_encryption or False, smtp_debug) smtp.sendmail(smtp_from, smtp_to_list, message.as_string()) finally: if smtp is not None: smtp.quit() except Exception, e: msg = _( "Mail delivery failed via SMTP server '%s'.\n%s: %s, Please check your mail setting" ) % (tools.ustr(smtp_server), e.__class__.__name__, tools.ustr(e)) raise osv.except_osv(_("Mail Delivery Failed"), msg)
def send_email(self, cr, uid, message, mail_server_id=None, smtp_server=None, smtp_port=None, smtp_user=None, smtp_password=None, smtp_encryption=None, smtp_debug=False, context=None): """Sends an email directly (no queuing). No retries are done, the caller should handle MailDeliveryException in order to ensure that the mail is never lost. If the mail_server_id is provided, sends using this mail server, ignoring other smtp_* arguments. If mail_server_id is None and smtp_server is None, use the default mail server (highest priority). If mail_server_id is None and smtp_server is not None, use the provided smtp_* arguments. If both mail_server_id and smtp_server are None, look for an 'smtp_server' value in server config, and fails if not found. :param message: the email.message.Message to send. The envelope sender will be extracted from the ``Return-Path`` or ``From`` headers. The envelope recipients will be extracted from the combined list of ``To``, ``CC`` and ``BCC`` headers. :param mail_server_id: optional id of ir.mail_server to use for sending. overrides other smtp_* arguments. :param smtp_server: optional hostname of SMTP server to use :param smtp_encryption: optional TLS mode, one of 'none', 'starttls' or 'ssl' (see ir.mail_server fields for explanation) :param smtp_port: optional SMTP port, if mail_server_id is not passed :param smtp_user: optional SMTP user, if mail_server_id is not passed :param smtp_password: optional SMTP password to use, if mail_server_id is not passed :param smtp_debug: optional SMTP debug flag, if mail_server_id is not passed :return: the Message-ID of the message that was just sent, if successfully sent, otherwise raises MailDeliveryException and logs root cause. """ smtp_from = message['Return-Path'] or message['From'] assert smtp_from, "The Return-Path or From header is required for any outbound email" # The email's "Envelope From" (Return-Path), and all recipient addresses must only contain ASCII characters. from_rfc2822 = extract_rfc2822_addresses(smtp_from) assert len(from_rfc2822) == 1, "Malformed 'Return-Path' or 'From' address - it may only contain plain ASCII characters" smtp_from = from_rfc2822[0] email_to = message['To'] email_cc = message['Cc'] email_bcc = message['Bcc'] smtp_to_list = filter(None, tools.flatten(map(extract_rfc2822_addresses,[email_to, email_cc, email_bcc]))) assert smtp_to_list, "At least one valid recipient address should be specified for outgoing emails (To/Cc/Bcc)" # Do not actually send emails in testing mode! if getattr(threading.currentThread(), 'testing', False): _logger.log(logging.TEST, "skip sending email in test mode") return message['Message-Id'] # Get SMTP Server Details from Mail Server mail_server = None if mail_server_id: mail_server = self.browse(cr, SUPERUSER_ID, mail_server_id) elif not smtp_server: mail_server_ids = self.search(cr, SUPERUSER_ID, [], order='sequence', limit=1) if mail_server_ids: mail_server = self.browse(cr, SUPERUSER_ID, mail_server_ids[0]) if mail_server: smtp_server = mail_server.smtp_host smtp_user = mail_server.smtp_user smtp_password = mail_server.smtp_pass smtp_port = mail_server.smtp_port smtp_encryption = mail_server.smtp_encryption smtp_debug = smtp_debug or mail_server.smtp_debug else: # we were passed an explicit smtp_server or nothing at all smtp_server = smtp_server or tools.config.get('smtp_server') smtp_port = tools.config.get('smtp_port', 25) if smtp_port is None else smtp_port smtp_user = smtp_user or tools.config.get('smtp_user') smtp_password = smtp_password or tools.config.get('smtp_password') if smtp_encryption is None and tools.config.get('smtp_ssl'): smtp_encryption = 'starttls' # STARTTLS is the new meaning of the smtp_ssl flag as of v7.0 if not smtp_server: raise osv.except_osv( _("Missing SMTP Server"), _("Please define at least one SMTP server, or provide the SMTP parameters explicitly.")) try: message_id = message['Message-Id'] # Add email in Maildir if smtp_server contains maildir. if smtp_server.startswith('maildir:/'): from mailbox import Maildir maildir_path = smtp_server[8:] mdir = Maildir(maildir_path, factory=None, create = True) mdir.add(message.as_string(True)) return message_id try: smtp = self.connect(smtp_server, smtp_port, smtp_user, smtp_password, smtp_encryption or False, smtp_debug) smtp.sendmail(smtp_from, smtp_to_list, message.as_string()) finally: try: # Close Connection of SMTP Server smtp.quit() except Exception: # ignored, just a consequence of the previous exception pass except Exception, e: msg = _("Mail delivery failed via SMTP server '%s'.\n%s: %s") % (tools.ustr(smtp_server), e.__class__.__name__, tools.ustr(e)) _logger.exception(msg) raise MailDeliveryException(_("Mail delivery failed"), msg)
def send_email(self, cr, uid, message, mail_server_id=None, smtp_server=None, smtp_port=None, smtp_user=None, smtp_password=None, smtp_encryption=None, smtp_debug=False, context=None): """Sends an email directly (no queuing). No retries are done, the caller should handle MailDeliveryException in order to ensure that the mail is never lost. If the mail_server_id is provided, sends using this mail server, ignoring other smtp_* arguments. If mail_server_id is None and smtp_server is None, use the default mail server (highest priority). If mail_server_id is None and smtp_server is not None, use the provided smtp_* arguments. If both mail_server_id and smtp_server are None, look for an 'smtp_server' value in server config, and fails if not found. :param message: the email.message.Message to send. The envelope sender will be extracted from the ``Return-Path`` or ``From`` headers. The envelope recipients will be extracted from the combined list of ``To``, ``CC`` and ``BCC`` headers. :param mail_server_id: optional id of ir.mail_server to use for sending. overrides other smtp_* arguments. :param smtp_server: optional hostname of SMTP server to use :param smtp_encryption: optional TLS mode, one of 'none', 'starttls' or 'ssl' (see ir.mail_server fields for explanation) :param smtp_port: optional SMTP port, if mail_server_id is not passed :param smtp_user: optional SMTP user, if mail_server_id is not passed :param smtp_password: optional SMTP password to use, if mail_server_id is not passed :param smtp_debug: optional SMTP debug flag, if mail_server_id is not passed :return: the Message-ID of the message that was just sent, if successfully sent, otherwise raises MailDeliveryException and logs root cause. """ smtp_from = message['Return-Path'] or message['From'] assert smtp_from, "The Return-Path or From header is required for any outbound email" # The email's "Envelope From" (Return-Path), and all recipient addresses must only contain ASCII characters. from_rfc2822 = extract_rfc2822_addresses(smtp_from) assert len(from_rfc2822) == 1, "Malformed 'Return-Path' or 'From' address - it may only contain plain ASCII characters" smtp_from = from_rfc2822[0] email_to = message['To'] email_cc = message['Cc'] email_bcc = message['Bcc'] smtp_to_list = filter(None, tools.flatten(map(extract_rfc2822_addresses,[email_to, email_cc, email_bcc]))) assert smtp_to_list, "At least one valid recipient address should be specified for outgoing emails (To/Cc/Bcc)" # Do not actually send emails in testing mode! if getattr(threading.currentThread(), 'testing', False): _logger.log(logging.TEST, "skip sending email in test mode") return message['Message-Id'] # Get SMTP Server Details from Mail Server mail_server = None if mail_server_id: mail_server = self.browse(cr, SUPERUSER_ID, mail_server_id) elif not smtp_server: mail_server_ids = self.search(cr, SUPERUSER_ID, [], order='sequence', limit=1) if mail_server_ids: mail_server = self.browse(cr, SUPERUSER_ID, mail_server_ids[0]) if mail_server: smtp_server = mail_server.smtp_host smtp_user = mail_server.smtp_user smtp_password = mail_server.smtp_pass smtp_port = mail_server.smtp_port smtp_encryption = mail_server.smtp_encryption smtp_debug = smtp_debug or mail_server.smtp_debug else: # we were passed an explicit smtp_server or nothing at all smtp_server = smtp_server or tools.config.get('smtp_server') smtp_port = tools.config.get('smtp_port', 25) if smtp_port is None else smtp_port smtp_user = smtp_user or tools.config.get('smtp_user') smtp_password = smtp_password or tools.config.get('smtp_password') if smtp_encryption is None and tools.config.get('smtp_ssl'): smtp_encryption = 'starttls' # STARTTLS is the new meaning of the smtp_ssl flag as of v7.0 #update by frank #smtp_user = smtp_from pid = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id._id smtp_user = self.pool.get('res.partner').browse(cr, uid, pid, context=context).email smtp_password = self.pool.get('res.users').browse(cr, uid, uid, context=context).x_mailpass #/update if not smtp_server: raise osv.except_osv( _("Missing SMTP Server"), _("Please define at least one SMTP server, or provide the SMTP parameters explicitly.")) try: message_id = message['Message-Id'] # Add email in Maildir if smtp_server contains maildir. if smtp_server.startswith('maildir:/'): from mailbox import Maildir maildir_path = smtp_server[8:] mdir = Maildir(maildir_path, factory=None, create = True) mdir.add(message.as_string(True)) return message_id try: smtp = self.connect(smtp_server, smtp_port, smtp_user, smtp_password, smtp_encryption or False, smtp_debug) #smtp = self.connect(smtp_server, smtp_port, smtp_from, smtp_password, smtp_encryption or False, smtp_debug) smtp.sendmail(smtp_from, smtp_to_list, message.as_string()) finally: try: # Close Connection of SMTP Server smtp.quit() except Exception: # ignored, just a consequence of the previous exception pass except Exception, e: msg = _("Mail delivery failed via SMTP server '%s'.\n%s: %s") % (tools.ustr(smtp_server), e.__class__.__name__, tools.ustr(e)) _logger.exception(msg) raise MailDeliveryException(_("Mail delivery failed"), msg)
def send_email(self, cr, uid, message, mail_server_id=None, smtp_server=None, smtp_port=None, smtp_user=None, smtp_password=None, smtp_encryption=None, smtp_debug=False, context=None): _logger.warn('Mandriil custom was here %s' % str(message)) """Sends an email directly (no queuing). No retries are done, the caller should handle MailDeliveryException in order to ensure that the mail is never lost. If the mail_server_id is provided, sends using this mail server, ignoring other smtp_* arguments. If mail_server_id is None and smtp_server is None, use the default mail server (highest priority). If mail_server_id is None and smtp_server is not None, use the provided smtp_* arguments. If both mail_server_id and smtp_server are None, look for an 'smtp_server' value in server config, and fails if not found. :param message: the email.message.Message to send. The envelope sender will be extracted from the ``Return-Path`` or ``From`` headers. The envelope recipients will be extracted from the combined list of ``To``, ``CC`` and ``BCC`` headers. :param mail_server_id: optional id of ir.mail_server to use for sending. overrides other smtp_* arguments. :param smtp_server: optional hostname of SMTP server to use :param smtp_encryption: optional TLS mode, one of 'none', 'starttls' or 'ssl' (see ir.mail_server fields for explanation) :param smtp_port: optional SMTP port, if mail_server_id is not passed :param smtp_user: optional SMTP user, if mail_server_id is not passed :param smtp_password: optional SMTP password to use, if mail_server_id is not passed :param smtp_debug: optional SMTP debug flag, if mail_server_id is not passed :return: the Message-ID of the message that was just sent, if successfully sent, otherwise raises MailDeliveryException and logs root cause. """ smtp_from = message['Return-Path'] or message['From'] assert smtp_from, "The Return-Path or From header is required for any outbound email" # The email's "Envelope From" (Return-Path), and all recipient addresses must only contain ASCII characters. from_rfc2822 = extract_rfc2822_addresses(smtp_from) assert from_rfc2822, ( "Malformed 'Return-Path' or 'From' address: %r - " "It should contain one valid plain ASCII email") % smtp_from # use last extracted email, to support rarities like 'Support@MyComp <*****@*****.**>' smtp_from = from_rfc2822[-1] email_to = message['To'] email_cc = message['Cc'] email_bcc = message['Bcc'] smtp_to_list = filter( None, tools.flatten( map(extract_rfc2822_addresses, [email_to, email_cc, email_bcc]))) assert smtp_to_list, self.NO_VALID_RECIPIENT x_forge_to = message['X-Forge-To'] if x_forge_to: # `To:` header forged, e.g. for posting on mail.groups, to avoid confusion del message['X-Forge-To'] del message['To'] # avoid multiple To: headers! message['To'] = x_forge_to # Do not actually send emails in testing mode! if getattr(threading.currentThread(), 'testing', False): _test_logger.info("skip sending email in test mode") return message['Message-Id'] # Get SMTP Server Details from Mail Server mail_server = None if mail_server_id: mail_server = self.browse(cr, SUPERUSER_ID, mail_server_id) elif not smtp_server: mail_server_ids = self.search(cr, SUPERUSER_ID, [], order='sequence', limit=1) if mail_server_ids: mail_server = self.browse(cr, SUPERUSER_ID, mail_server_ids[0]) if mail_server: smtp_server = mail_server.smtp_host smtp_user = mail_server.smtp_user smtp_password = mail_server.smtp_pass smtp_port = mail_server.smtp_port smtp_encryption = mail_server.smtp_encryption smtp_debug = smtp_debug or mail_server.smtp_debug else: # we were passed an explicit smtp_server or nothing at all smtp_server = smtp_server or tools.config.get('smtp_server') smtp_port = tools.config.get( 'smtp_port', 25) if smtp_port is None else smtp_port smtp_user = smtp_user or tools.config.get('smtp_user') smtp_password = smtp_password or tools.config.get('smtp_password') if smtp_encryption is None and tools.config.get('smtp_ssl'): smtp_encryption = 'starttls' # STARTTLS is the new meaning of the smtp_ssl flag as of v7.0 if not smtp_server: raise osv.except_osv( _("Missing SMTP Server"), _("Please define at least one SMTP server, or provide the SMTP parameters explicitly." )) message_id = message['Message-Id'] # Hook 1 if smtp_server == 'mandrill': if tools.config.get('mandrill_key', False): return self.send_mandrill(cr, SUPERUSER_ID, message) else: _logger.warn( 'You set SMTP server as mandrill but not sent mandril API key in Odoo config file. Use standart Odoo core folow. Please set param mandrill_key in config file' ) # Hook 1 # Hook 2 if smtp_server == 'smtp.mandrillapp.com': user_obj = self.pool['res.users'].browse(cr, SUPERUSER_ID, uid) normal_from = peplace_email(message['From'], user_obj.login) del message['From'] del message['Reply-To'] message['From'] = normal_from message['Reply-To'] = normal_from _logger.warn('smtp.mandrillapp.com message %s' % str(message)) # Hook 2 try: # Add email in Maildir if smtp_server contains maildir. if smtp_server.startswith('maildir:/'): from mailbox import Maildir maildir_path = smtp_server[8:] mdir = Maildir(maildir_path, factory=None, create=True) mdir.add(message.as_string(True)) return message_id smtp = None try: smtp = self.connect(smtp_server, smtp_port, smtp_user, smtp_password, smtp_encryption or False, smtp_debug) rez = smtp.sendmail(smtp_from, smtp_to_list, message.as_string()) _logger.warn('SMTP send Res %s' % str(rez)) finally: if smtp is not None: smtp.quit() except Exception, e: msg = _("Mail delivery failed via SMTP server '%s'.\n%s: %s") % ( tools.ustr(smtp_server), e.__class__.__name__, tools.ustr(e)) _logger.error(msg) raise MailDeliveryException(_("Mail Delivery Failed"), msg)