Example #1
0
 def apply(cls, obj, routes, message, data=None):
     result = []
     recipients = tools.email_split(','.join([
         decode_header(message, 'Delivered-To'),
         decode_header(message, 'To'),
         decode_header(message, 'Cc'),
         decode_header(message, 'Resent-To'),
         decode_header(message, 'Resent-Cc')
     ]))
     logger.info('Checking incoming for %r',
                 recipients,
                 extra=dict(
                     delivered_to=message.get('Delivered-To'),
                     to=message.get('To'),
                     cc=message.get('Cc'),
                 ))
     for route in routes:
         alias = route[-1] if len(route) == 5 else None
         if alias:
             if alias.alias_domain:
                 alias_mail = '%s@%s' % (alias.alias_name,
                                         alias.alias_domain)
                 if recipients and any(alias_mail.lower() == rcpt.lower()
                                       for rcpt in recipients):
                     result.append(route)
                 else:
                     logger.warning('Discarding alias %r', alias_mail)
             else:
                 result.append(route)
         else:
             result.append(route)
     routes[:] = result
     return routes
Example #2
0
 def query(cls, obj, message):
     headers = [
         decode_header(message, 'To'),
         decode_header(message, 'Cc'),
         decode_header(message, 'Delivered-To')
     ]
     if message['Auto-Submitted']:
         # If the message we're receiving is not an auto-submitted one,
         # it's not a cycle.  This would be the case of:
         #
         # 1. Party A sends an auto-submitted message
         # 2. Odoo resends that message to Party B.
         # 3. Party B does not auto-respond, and that's just fine.
         # 4. Later Party B (the human) replies but uses the address in the
         #    auto-submitted message to do it.
         #
         # In this case, although the address would be a breaking cycle is
         # not actually a cycle.
         #
         # The only problem with this is there's a auto-responder that does
         # not use the Auto-Submitted header.  As we've seen some use the
         # From address as the recipient for the auto-submitted message and
         # that's not what the RFC recommends.  However, the previous
         # depiction is likely to happen if we ever allow an auto-submitted
         # message to go out (as we do).
         #
         recipients = [
             email for _, email in getaddresses(headers)
             if cls._is_breaking_cycle_address(obj, email)
         ]
         # If any recipient is a breaking cycle address, break it!
         return bool(recipients)
     else:
         return False
Example #3
0
 def query(cls, obj, message):
     headers = [
         decode_header(message, 'To'),
         decode_header(message, 'Cc'),
         decode_header(message, 'Delivered-To')
     ]
     recipients = [email for _, email in getaddresses(headers)]
     match = cls._find_replyto(obj, recipients)
     return match is not None, match
Example #4
0
def get_recipients(message, include_cc=False):
    'Return the list of (name, email) of the message recipients.'
    # TODO: use openerp.tools.email_split(text)
    raw_recipients = [decode_header(message, 'To')]
    if include_cc:
        raw_recipients.append(decode_header(message, 'Cc'))
    recipients = [
        addr for addr in getaddresses(raw_recipients) if valid_email(*addr)
    ]
    return recipients
Example #5
0
    def _get_bounce_address(cls, obj, message, mail, email_to):
        '''Compute the bounce address.

        '''
        if mail.email_from == VOID_EMAIL_ADDRESS:
            # This is a bounce notification, so don't we should not generate a
            # VERP address.
            return None
        if not mail.mail_message_id:
            # I can't provide a VERP bounce address without a message id.
            return None
        assert mail.mail_message_id.id == message.id
        bounce_alias = get_bounce_alias(obj)
        if not bounce_alias:
            return None
        get_param = obj.env['ir.config_parameter'].get_param
        domain = get_param('mail.catchall.domain')
        if not domain or not message.thread_index:
            return None
        Records = obj.env['xopgi.verp.record']
        record = Records.create(dict(
            bounce_alias=bounce_alias,
            message_id=message.id,
            thread_index=message.thread_index,
            recipient=decode_header(
                # decode assumes str, but mail.email_to may yield unicode
                safe_encode(mail.email_to or email_to)
            )
        ))
        return '%s+%s@%s' % (bounce_alias, record.reference, domain)
Example #6
0
    def message_route(self,
                      message,
                      message_dict,
                      model=None,
                      thread_id=None,
                      custom_values=None):
        ''' Remove original Message-ID if message References has both
        original and encoded.

        It only happen when is replying a message treated on
        OriginalReferenceTransport implemented on this module.

        '''
        # This better here and not on a Router to remove unwanted references
        # before super's message_route call, or else it is possible to get a
        # wrong route and miss the right one.
        references = decode_header(message, 'References')
        thread_references = references or ''
        msg_references = mail_header_msgid_re.findall(thread_references)
        if msg_references and len(msg_references) > 1:
            result_references = msg_references[:]
            for ref in msg_references:
                original_ref = message_id_is_encoded(self, ref)
                if original_ref and original_ref in references:
                    result_references.remove(original_ref)
            del message['References']
            message['References'] = ' '.join(result_references)
        result = super(MailThread,
                       self).message_route(message,
                                           message_dict,
                                           model=model,
                                           thread_id=thread_id,
                                           custom_values=custom_values)
        return result
Example #7
0
 def message_parse(self, message, save_original=False):
     result = super(MailThreadExpand,
                    self).message_parse(message,
                                        save_original=save_original)
     # Save all original recipients on mail message cc field.
     raw_recipients = []
     for header in ('To', 'Cc'):
         raw_recipients.append(decode_header(message, header))
     recipients = []
     for recipient in raw_recipients:
         recipients.extend(email_split_and_format(recipient))
     result['recipients'] = ', '.join(recipients)
     return result
Example #8
0
    def query(cls, obj, message):
        ''' If Message-ID or any reference is encoded decode and add it to
        References to allow correct threading.

        '''
        refs = decode_header(message, 'References')
        if refs:
            references = mail_header_msgid_re.findall(refs)
        else:
            references = []
        message_id = message.get('Message-ID')
        if message_id:
            iter_references = references + [message_id]
        else:
            iter_references = references[:]
        result = False
        for ref in iter_references:
            original_ref = message_id_is_encoded(obj, ref)
            if original_ref and original_ref not in references:
                references.append(original_ref)
                result = True
        return result, dict(references=' '.join(references))
Example #9
0
 def apply(cls, obj, routes, message, data=None):
     result = []
     raw_recipients = (decode_header(message,
                                     'Delivered-To',
                                     separator=COMMA),
                       decode_header(message, 'To', separator=COMMA),
                       decode_header(message, 'Cc', separator=COMMA),
                       decode_header(message, 'Resent-To', separator=COMMA),
                       decode_header(message, 'Resent-Cc', separator=COMMA))
     recipients = [
         rcpt for header in raw_recipients
         for rcpt in tools.email_split(header)
     ]
     for route in routes:
         alias = route[-1] if len(route) == 5 else None
         if alias:
             if alias.alias_domain:
                 alias_mail = '%s@%s' % (alias.alias_name,
                                         alias.alias_domain)
                 if recipients and any(alias_mail.lower() == rcpt.lower()
                                       for rcpt in recipients):
                     result.append(route)
                 else:
                     logger.warning(
                         'Discarding alias %r',
                         alias_mail,
                         extra=dict(
                             route=route,
                             recipients=recipients,
                             raw_recipients=raw_recipients,
                             alias_name=alias.alias_name,
                             alias_domain=alias.alias_domain,
                             message_headers=dict(
                                 to=message['To'],
                                 delivered_to=message['Delivered-To'],
                                 cc=message['Cc'],
                                 resent_to=message['Resent-To'],
                                 resent_cc=message['Resent-Cc'],
                                 decoded_to=decode_header(message,
                                                          'To',
                                                          separator=COMMA),
                                 decoded_delivered_to=decode_header(
                                     message,
                                     'Delivered-To',
                                     separator=COMMA),
                                 decoded_cc=decode_header(message,
                                                          'Cc',
                                                          separator=COMMA),
                                 decoded_resent_to=decode_header(
                                     message, 'Resent-To', separator=COMMA),
                                 decoded_resent_cc=decode_header(
                                     message, 'Resent-Cc', separator=COMMA),
                             ),
                             stack=True,
                         ))
             else:
                 result.append(route)
         else:
             result.append(route)
     routes[:] = result
     return routes