diff --git a/odoo/addons/base/models/ir_mail_server.py b/odoo/addons/base/models/ir_mail_server.py index 18e8d982ba9..7bd72171205 100644 --- a/odoo/addons/base/models/ir_mail_server.py +++ b/odoo/addons/base/models/ir_mail_server.py @@ -437,6 +437,51 @@ class IrMailServer(models.Model): return "%s@%s" % (email_from, domain) return tools.config.get("email_from") + def _prepare_email_message(self, message): + """Prepare the SMTP information (from, to, message) before sending. + + :param message: the email.message.Message to send, information like the + Return-Path, the From, etc... will be used to find the smtp_from and to smtp_to + :return: smtp_from, smtp_to_list, message + smtp_from: email to used during the authentication to the mail server + smtp_to_list: list of email address which will receive the email + message: the email.message.Message to send + """ + + # 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'] + del message['Bcc'] + + smtp_to_list = [ + address + for base in [email_to, email_cc, email_bcc] + for address in extract_rfc2822_addresses(base) + if address + ] + 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 + + return smtp_from, smtp_to_list, message + @api.model def send_email(self, message, mail_server_id=None, smtp_server=None, smtp_port=None, smtp_user=None, smtp_password=None, smtp_encryption=None, @@ -473,37 +518,7 @@ class IrMailServer(models.Model): :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'] - del message['Bcc'] - - smtp_to_list = [ - address - for base in [email_to, email_cc, email_bcc] - for address in extract_rfc2822_addresses(base) - if address - ] - 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 + smtp_from, smtp_to_list, message = self._prepare_email_message(message) # Do not actually send emails in testing mode! if getattr(threading.currentThread(), 'testing', False) or self.env.registry.in_test_mode():