Esempio n. 1
0
    def test_decode_smtp_header_email(self):
        cases = [
            # In == Out for trivial ASCII cases
            ('Joe Doe <*****@*****.**>', 'Joe Doe <*****@*****.**>'),
            ('Joe <*****@*****.**>, Mike <*****@*****.**>',
             'Joe <*****@*****.**>, Mike <*****@*****.**>'),

            # Same thing, but RFC822 quoted-strings must be preserved
            ('"Doe, Joe" <*****@*****.**>', '"Doe, Joe" <*****@*****.**>'),
            ('"Doe, Joe" <*****@*****.**>, "Foo, Mike" <*****@*****.**>',
             '"Doe, Joe" <*****@*****.**>, "Foo, Mike" <*****@*****.**>'),

            # RFC2047-encoded words have to be quoted after decoding, because
            # they are considered RFC822 `words` i.e. atom or quoted-string only!
            # It's ok to quote a single word even if unnecessary.
            # Example values produced by `formataddr((name, address), 'ascii')`
            ("=?utf-8?b?Sm/DqQ==?= <*****@*****.**>", '"Joé" <*****@*****.**>'),
            ("=?utf-8?b?Sm/DqQ==?= <*****@*****.**>, =?utf-8?b?RsO2w7YsIE1pa2U=?= <*****@*****.**>",
             '"Joé" <*****@*****.**>, "Föö, Mike" <*****@*****.**>'),
            ('=?utf-8?b?RG/DqSwg?= =?US-ASCII?Q?Joe?= <*****@*****.**>',
             '"Doé, ""Joe" <*****@*****.**>'),

            # Double-quotes may appear in the encoded form and /must/ be turned
            # into a RFC2822 quoted-pair (i.e. escaped)
            #   "Trevor \"Banana\" Dumoulin" <*****@*****.**>
            ('=?utf-8?b?VHLDqXZvciAiQmFuYW5hIiBEdW1vdWxpbg==?= <*****@*****.**>',
             '"Trévor \\"Banana\\" Dumoulin" <*****@*****.**>'),
        ]

        for test, truth in cases:
            self.assertEqual(decode_smtp_header(test, quoted=True), truth)
Esempio n. 2
0
    def _attachment_invoice(self, msg_txt):
        body, attachments = self.env['mail.thread']._message_extract_payload(msg_txt)
        from_address = tools.decode_smtp_header(msg_txt.get('from'))
        for attachment in attachments:
            split_attachment = attachment.fname.rpartition('.')
            if len(split_attachment) < 3:
                _logger.info('E-invoice filename not compliant: %s', attachment.fname)
                continue
            attachment_name = split_attachment[0]
            attachment_ext = split_attachment[2]
            split_underscore = attachment_name.rsplit('_', 2)
            if len(split_underscore) < 2:
                _logger.info('E-invoice filename not compliant: %s', attachment.fname)
                continue

            if attachment_ext != 'zip':
                if split_underscore[1] in ['RC', 'NS', 'MC', 'MT', 'EC', 'SE', 'NE', 'DT']:
                    # we have a receipt
                    self._message_receipt_invoice(split_underscore[1], attachment)
                elif re.search("([A-Z]{2}[A-Za-z0-9]{2,28}_[A-Za-z0-9]{0,5}.(xml.p7m|xml))", attachment.fname):
                    # we have a new E-invoice
                    self._create_invoice_from_mail(attachment.content, attachment.fname, from_address)
            else:
                if split_underscore[1] == 'AT':
                    # Attestazione di avvenuta trasmissione della fattura con impossibilità di recapito
                    self._message_AT_invoice(attachment)
                else:
                    _logger.info('New E-invoice in zip file: %s', attachment.fname)
                    self._create_invoice_from_mail_with_zip(attachment, from_address)
Esempio n. 3
0
    def _attachment_invoice(self, msg_txt):
        body, attachments = self.env['mail.thread']._message_extract_payload(msg_txt)
        from_address = tools.decode_smtp_header(msg_txt.get('from'))
        for attachment in attachments:
            split_attachment = attachment.fname.rpartition('.')
            if len(split_attachment) < 3:
                _logger.info('E-invoice filename not compliant: %s', attachment.fname)
                continue
            attachment_name = split_attachment[0]
            attachment_ext = split_attachment[2]
            split_underscore = attachment_name.rsplit('_', 2)
            if len(split_underscore) < 2:
                _logger.info('E-invoice filename not compliant: %s', attachment.fname)
                continue

            if attachment_ext != 'zip':
                if split_underscore[1] in ['RC', 'NS', 'MC', 'MT', 'EC', 'SE', 'NE', 'DT']:
                    # we have a receipt
                    self._message_receipt_invoice(split_underscore[1], attachment)
                elif re.search("([A-Z]{2}[A-Za-z0-9]{2,28}_[A-Za-z0-9]{0,5}.(xml.p7m|xml))", attachment.fname):
                    # we have a new E-invoice
                    self._create_invoice_from_mail(attachment.content, attachment.fname, from_address)
            else:
                if split_underscore[1] == 'AT':
                    # Attestazione di avvenuta trasmissione della fattura con impossibilità di recapito
                    self._message_AT_invoice(attachment)
                else:
                    _logger.info('New E-invoice in zip file: %s', attachment.fname)
                    self._create_invoice_from_mail_with_zip(attachment, from_address)
Esempio n. 4
0
 def message_route_process(self, message, message_dict, routes):
     """ Override to update the parent mail statistics. The parent is found
     by using the References header of the incoming message and looking for
     matching message_id in mail.mail.statistics. """
     if message.get('References'):
         message_ids = [x.strip() for x in decode_smtp_header(message['References']).split()]
         self.env['mail.mail.statistics'].set_replied(mail_message_ids=message_ids)
     return super(MailThread, self).message_route_process(message, message_dict, routes)
Esempio n. 5
0
 def message_route_process(self, message, message_dict, routes):
     """ Override to update the parent mail statistics. The parent is found
     by using the References header of the incoming message and looking for
     matching message_id in mail.mail.statistics. """
     if message.get('References'):
         message_ids = [x.strip() for x in decode_smtp_header(message['References']).split()]
         self.env['mail.mail.statistics'].set_replied(mail_message_ids=message_ids)
     return super(MailThread, self).message_route_process(message, message_dict, routes)
Esempio n. 6
0
 def message_parse(self, message, save_original=False):
     msg_dict = super().message_parse(message, save_original)
     if not isinstance(message, Message):
         # message_from_string works on a native str
         message = pycompat.to_native(message)
         message = email.message_from_string(message)
     msg_dict['reply_to'] = tools.decode_smtp_header(message.get('Reply-To'))
     return msg_dict
 def message_parse(self, message, save_original=False):
     msg_dict = super(MailThread, self)\
         .message_parse(message, save_original)
     original_from = tools.decode_smtp_header(
         message.get('X-Original-From'))
     if original_from:
         msg_dict['email_from'] = original_from
         msg_dict['from'] = original_from
     return msg_dict
Esempio n. 8
0
    def message_route_process(self, message, message_dict, routes):
        """ Override to update the parent mail statistics. The parent is found
        by using the References header of the incoming message and looking for
        matching message_id in mail.mail.statistics. """
        if routes:
            references_msg_id_list = []
            if message.get('References'):
                references_msg_id_list = [
                    x.strip() for x in tools.mail_header_msgid_re.findall(
                        tools.decode_smtp_header(message['References']))
                ]
            elif message.get('In-Reply-To'):
                references_msg_id_list = [
                    tools.decode_smtp_header(message['In-Reply-To'].strip())
                ]

            if references_msg_id_list:
                self.env['mail.mail.statistics'].set_opened(
                    mail_message_ids=references_msg_id_list)
                self.env['mail.mail.statistics'].set_replied(
                    mail_message_ids=references_msg_id_list)
        return super(MailThread,
                     self).message_route_process(message, message_dict, routes)
 def _message_extract_payload(self, message, save_original=False):
     body, attachments = super()._message_extract_payload(
         message, save_original)
     if body:
         # Only remove signature for an e-mail coming from our domain
         email_from = tools.decode_smtp_header(message.get('from'),
                                               quoted=True)
         email_from = parseaddr(email_from)[1]
         email_domain = email_from.partition('@')[2]
         catchall_domain = self.env['ir.config_parameter'].sudo().get_param(
             "mail.catchall.domain")
         if email_domain == catchall_domain:
             body = self._remove_gmail_signatures(body)
     return body, attachments
Esempio n. 10
0
    def fetch_mail(self):
        for server in self:
            count, failed = 0, 0
            pop_server = None
            if server.type == 'pop':
                _logger.info('Server tpye is POP')
                try:
                    while True:
                        pop_server = server.connect()
                        (num_messages, total_size) = pop_server.stat()
                        pop_server.list()
                        _logger.info('Server tpye is POP inside while')
                        _logger.info('total_size = %d', total_size)
                        _logger.info('num_messages = %d', num_messages)
                        for num in range(
                                1,
                                min(MAX_POP_MESSAGES, num_messages) + 1):
                            _logger.info(
                                'Server tpye is POP inside while INSIDE FOR')
                            (header, messages, octets) = pop_server.retr(num)
                            message = (b'\n').join(messages)
                            res_id = None
                            response = {
                                'errorCode': 100,
                                'message': 'File Uploaded Successfully'
                            }
                            try:
                                if isinstance(message, xmlrpclib.Binary):
                                    message = bytes(message.data)
                                if isinstance(message, pycompat.text_type):
                                    message = message.encode('utf-8')
                                extract = getattr(email, 'message_from_bytes',
                                                  email.message_from_string)
                                message = extract(message)
                                if not isinstance(message, Message):
                                    message = pycompat.to_native(message)
                                    message = email.message_from_string(
                                        message)
                                email_to = tools.decode_message_header(
                                    message, 'To')
                                match = re.search(r'[\w\.-]+@[\w\.-]+',
                                                  email_to)
                                email_to = str(match.group(0))
                                _logger.info('Email to %r', email_to)
                                # if email_to == INCOMING_EMAIL_ID:
                                _Attachment = namedtuple(
                                    'Attachment', ('fname', 'content', 'info'))
                                attachments = []
                                body = u''
                                email_from = tools.decode_message_header(
                                    message, 'From')
                                _logger.info('Email from %r', email_from)
                                match = re.search(r'[\w\.-]+@[\w\.-]+',
                                                  email_from)
                                email_from = str(match.group(0))
                                subject = tools.decode_message_header(
                                    message, 'Subject')
                                tmpl_type = None
                                if 'Inventory' in subject:
                                    tmpl_type = "Inventory"
                                elif 'Requirement' in subject:
                                    tmpl_type = "Requirement"
                                if message.get_content_maintype() != 'text':
                                    alternative = False
                                    for part in message.walk():
                                        if part.get_content_type(
                                        ) == 'multipart/alternative':
                                            alternative = True
                                        if part.get_content_maintype(
                                        ) == 'multipart':
                                            continue  # skip container
                                        filename = part.get_param(
                                            'filename', None,
                                            'content-disposition')
                                        if not filename:
                                            filename = part.get_param(
                                                'name', None)
                                        if filename:
                                            if isinstance(filename, tuple):
                                                filename = email.utils.collapse_rfc2231_value(
                                                    filename).strip()
                                            else:
                                                filename = tools.decode_smtp_header(
                                                    filename)
                                        encoding = part.get_content_charset()
                                        if filename and part.get('content-id'):
                                            inner_cid = part.get(
                                                'content-id').strip('><')
                                            attachments.append(
                                                _Attachment(
                                                    filename,
                                                    part.get_payload(
                                                        decode=True),
                                                    {'cid': inner_cid}))
                                            continue
                                        if filename or part.get(
                                                'content-disposition', ''
                                        ).strip().startswith('attachment'):
                                            attachments.append(
                                                _Attachment(
                                                    filename or 'attachment',
                                                    part.get_payload(
                                                        decode=True), {}))
                                            continue
                                        if part.get_content_type(
                                        ) == 'text/plain' and (not alternative
                                                               or not body):
                                            body = tools.append_content_to_html(
                                                body,
                                                tools.ustr(part.get_payload(
                                                    decode=True),
                                                           encoding,
                                                           errors='replace'),
                                                preserve=True)
                                        elif part.get_content_type(
                                        ) == 'text/html':
                                            body = tools.ustr(
                                                part.get_payload(decode=True),
                                                encoding,
                                                errors='replace')
                                        else:
                                            attachments.append(
                                                _Attachment(
                                                    filename or 'attachment',
                                                    part.get_payload(
                                                        decode=True), {}))
                                    if len(attachments) > 0:
                                        encoding = message.get_content_charset(
                                        )
                                        plain_text = html2text.HTML2Text()
                                        message_payload = plain_text.handle(
                                            tools.ustr(body,
                                                       encoding,
                                                       errors='replace'))
                                        if '- Forwarded message -' in message_payload:
                                            messages = message_payload.split(
                                                '- Forwarded message -')
                                            _logger.info(
                                                'Forwarded message payload: %r',
                                                messages)
                                            total_parts = len(messages)
                                            originator_part = messages[
                                                total_parts - 1]
                                            _logger.info(
                                                'originator_part: %r',
                                                originator_part)
                                            match = re.search(
                                                r'[\w\.-]+@[\w\.-]+',
                                                originator_part)
                                            _logger.info('match: %r', match)
                                            if match:
                                                email_from_domain = re.search(
                                                    "@[\w.]+",
                                                    email_from).group(0)
                                                _logger.info(
                                                    'email_from_domain: %r',
                                                    email_from_domain)
                                                email_to_domain = re.search(
                                                    "@[\w.]+",
                                                    email_to).group(0)
                                                _logger.info(
                                                    'email_to_domain: %r',
                                                    email_to_domain)
                                                if email_to_domain != email_from_domain:
                                                    email_from = None
                                                else:
                                                    email_from = str(
                                                        match.group(0))
                                                    _logger.info(
                                                        'email_to_domain email_from: %r',
                                                        email_from)
                                        #_logger.info('message payload: %r %r', message_payload, email_from)
                                        if not email_from is None:
                                            users_model = self.env[
                                                'res.partner'].search([
                                                    ("email", "=", email_from)
                                                ])
                                            if users_model:
                                                if len(users_model) == 1:
                                                    user_attachment_dir = ATTACHMENT_DIR + str(
                                                        datetime.now(
                                                        ).strftime("%d%m%Y")
                                                    ) + "/" + str(
                                                        users_model.id) + "/"
                                                    if not os.path.exists(
                                                            os.path.dirname(
                                                                user_attachment_dir
                                                            )):
                                                        try:
                                                            os.makedirs(
                                                                os.path.
                                                                dirname(
                                                                    user_attachment_dir
                                                                ))
                                                        except OSError as exc:
                                                            if exc.errno != errno.EEXIST:
                                                                raise
                                                    for attachment in attachments:
                                                        filename = getattr(
                                                            attachment,
                                                            'fname')
                                                        if not filename is None:
                                                            try:
                                                                file_contents_bytes = getattr(
                                                                    attachment,
                                                                    'content')
                                                                file_path = user_attachment_dir + str(
                                                                    filename)
                                                                file_ref = open(
                                                                    str(file_path
                                                                        ),
                                                                    "wb+")
                                                                file_ref.write(
                                                                    file_contents_bytes
                                                                )
                                                                file_ref.close(
                                                                )
                                                                response = self.env[
                                                                    'sps.document.process'].process_document(
                                                                        users_model,
                                                                        file_path,
                                                                        tmpl_type,
                                                                        filename,
                                                                        'Email'
                                                                    )
                                                            except Exception as e:
                                                                _logger.info(
                                                                    str(e))
                                                else:
                                                    _logger.error(
                                                        'Presents Same Email Id for multiple users %r',
                                                        email_from)
                                                    response = dict(
                                                        errorCode=101,
                                                        message=
                                                        'Presents Same Email Id for multiple users : '
                                                        + str(email_from))
                                            else:
                                                _logger.info(
                                                    'user not found for %r',
                                                    email_from)
                                                response = dict(
                                                    errorCode=102,
                                                    message=
                                                    'User not found for : ' +
                                                    str(email_from))
                                        else:
                                            _logger.info(
                                                'domain not matched for forwarded email'
                                            )
                                            response = dict(
                                                errorCode=103,
                                                message=
                                                'Domain not matched for forwarded email : '
                                                + str(email_from))
                                    else:
                                        _logger.info("No attachements found")
                                        response = dict(
                                            errorCode=104,
                                            message='No attachements found : '
                                            + str(email_from))
                                else:
                                    _logger.info('Not a Multipart email')
                                    response = dict(
                                        errorCode=105,
                                        message='Not a Multipart email' +
                                        str(email_from))
                                pop_server.dele(num)

                                if "errorCode" in response:
                                    self.send_mail(
                                        "Sending Email Response as " +
                                        str(response['message']) +
                                        " for user " + str(email_from))

                            except Exception:
                                _logger.info(
                                    'Failed to process mail from %s server %s.',
                                    server.type,
                                    server.name,
                                    exc_info=True)
                                failed += 1

                            if res_id and server.action_id:
                                server.action_id.with_context({
                                    'active_id':
                                    res_id,
                                    'active_ids': [res_id],
                                    'active_model':
                                    self.env.context.get(
                                        "thread_model", server.object_id.model)
                                }).run()
                            self.env.cr.commit()
                        _logger.info('num_messages = %d', num_messages)
                        if num_messages < MAX_POP_MESSAGES:
                            break
                        pop_server.quit()
                        _logger.info(
                            "Fetched %d email(s) on %s server %s; %d succeeded, %d failed.",
                            num_messages, server.type, server.name,
                            (num_messages - failed), failed)
                except Exception:
                    _logger.info(
                        "General failure when trying to fetch mail from %s server %s.",
                        server.type,
                        server.name,
                        exc_info=True)
                finally:
                    _logger.info('Server tpye is POP inside finally')
                    if pop_server:
                        pop_server.quit()
            server.write({'date': fields.Datetime.now()})

        return super(IncomingMailCronModel, self).fetch_mail()