From 5d4707df02b2f07c0a5f1492998984aa4e2a267f Mon Sep 17 00:00:00 2001 From: xtremxpert Date: Wed, 22 Jan 2025 11:29:29 -0500 Subject: [PATCH] img inline using eml convert then mail --- .../models/ir_attachment.py | 170 +++++++++++------- 1 file changed, 105 insertions(+), 65 deletions(-) diff --git a/msg_attachments_to_mail_message/models/ir_attachment.py b/msg_attachments_to_mail_message/models/ir_attachment.py index 38e9556..836fd89 100644 --- a/msg_attachments_to_mail_message/models/ir_attachment.py +++ b/msg_attachments_to_mail_message/models/ir_attachment.py @@ -5,6 +5,11 @@ import base64 import logging from odoo.tools.translate import _ from email.message import EmailMessage +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText +from email.mime.image import MIMEImage +from email.mime.base import MIMEBase +from email import encoders import lxml.html import re from odoo.tools import email_normalize, email_split @@ -49,8 +54,103 @@ class IrAttachment(models.Model): # Replace any combination of whitespace (including newlines) with a single space return ' '.join(str(value).split()) + def _msg_to_eml(self, msg_data): + """Convert MSG file data to EML format.""" + try: + # Read the MSG file + msg_file = extract_msg.Message(msg_data) + _logger.info('Converting MSG to EML - Subject: %s, From: %s, To: %s', + msg_file.subject, msg_file.sender, msg_file.to) + + # Create email message + email_msg = MIMEMultipart('related') + + # Add headers + email_msg['Subject'] = self._clean_header_value(msg_file.subject) or "No Subject" + email_msg['From'] = self._clean_header_value(msg_file.sender) + email_msg['To'] = self._clean_header_value(msg_file.to) + email_msg['Cc'] = self._clean_header_value(msg_file.cc) if msg_file.cc else None + email_msg['Date'] = msg_file.date.strftime('%a, %d %b %Y %H:%M:%S %z') if msg_file.date else formatdate(localtime=True) + + # Add original MSG headers if present + for header in ['Message-ID', 'In-Reply-To', 'References']: + if header.lower() in msg_file.header: + header_value = self._clean_header_value(msg_file.header[header.lower()]) + if header_value: # Only add header if it has a value + email_msg[header] = header_value + + # Set the body + if msg_file.body: + body = msg_file.body + + # Si ce n'est pas déjà du HTML mais contient des CIDs, convertir en HTML + if ' + body = body.replace('\n', '
') + # Convertir les références CID en balises img + import re + body = re.sub( + r'\[cid:([^\]]+)\]', + lambda m: f'{m.group(1)}', + body + ) + # Envelopper dans du HTML + body = f'{body}' + + # Clean HTML if needed + if '')}>") + mime_part.add_header('Content-Disposition', 'inline', filename=filename) + _logger.info('Adding inline image with CID: %s, filename: %s', attachment.contentId, filename) + else: + # Fallback pour les non-images avec CID + mime_part = MIMEBase(maintype, subtype) + mime_part.set_payload(attachment.data) + encoders.encode_base64(mime_part) + mime_part.add_header('Content-ID', f"<{attachment.contentId.strip('<>')}>") + mime_part.add_header('Content-Disposition', 'inline', filename=filename) + else: + # Pièce jointe normale + maintype, subtype = (attachment.mimetype or 'application/octet-stream').split('/', 1) + mime_part = MIMEBase(maintype, subtype) + mime_part.set_payload(attachment.data) + encoders.encode_base64(mime_part) + mime_part.add_header('Content-Disposition', 'attachment', filename=filename) + + email_msg.attach(mime_part) + + return email_msg.as_string() + + except Exception as e: + _logger.error('Error converting MSG to EML: %s', str(e), exc_info=True) + raise + def process_msg_as_email(self): - """Convert MSG file to RFC822 email format and process it using Odoo's mail module.""" + """Convert MSG file to EML and process it using Odoo's mail module.""" self.ensure_one() _logger.info('Starting MSG processing for file: %s (model: %s, res_id: %s)', self.name, self.res_model, self.res_id) @@ -62,69 +162,9 @@ class IrAttachment(models.Model): return False try: - # Read the MSG file - _logger.info('Decoding MSG file data') + # Convert MSG to EML msg_data = base64.b64decode(self.datas) - msg_file = extract_msg.Message(msg_data) - _logger.info('MSG file info - Subject: %s, From: %s, To: %s', - msg_file.subject, msg_file.sender, msg_file.to) - - # Convert MSG to email format - email_msg = EmailMessage() - - # Add headers - email_msg['Subject'] = self._clean_header_value(msg_file.subject) or _("No Subject") - email_msg['From'] = self._clean_header_value(msg_file.sender) - email_msg['To'] = self._clean_header_value(msg_file.to) - email_msg['Cc'] = self._clean_header_value(msg_file.cc) - email_msg['Date'] = msg_file.date.strftime('%a, %d %b %Y %H:%M:%S %z') if msg_file.date else formatdate(localtime=True) - - # Add original MSG headers if present - for header in ['Message-ID', 'In-Reply-To', 'References']: - if header.lower() in msg_file.header: - email_msg[header] = self._clean_header_value(msg_file.header[header.lower()]) - - # Set the body - if msg_file.body: - _logger.info('Processing message body') - body = msg_file.body - # Convert [cid:xxx] to proper HTML img tags if needed - cid_pattern = r'\[cid:([^\]]+)\]' - body = re.sub(cid_pattern, r'', body) - # Clean HTML if needed - if '') - headers['Content-ID'] = f'<{cid}>' - - email_msg.add_attachment( - attachment.data, - maintype=maintype, - subtype=subtype, - filename=filename, - headers=headers - ) + eml_content = self._msg_to_eml(msg_data) # Process using Odoo's standard mail handling thread_model = self.env[self.res_model] if self.res_model else self.env['mail.thread'] @@ -141,10 +181,10 @@ class IrAttachment(models.Model): 'mail_thread_quote': False, } - # Process the email using Odoo's standard message_process + # Process the EML using Odoo's standard message_process thread_id = thread_model.with_context(**context).message_process( model=self.res_model, - message=email_msg.as_bytes(), + message=eml_content, custom_values={ 'res_id': self.res_id, 'model': self.res_model,