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
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
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
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
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)
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
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
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))
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