From 6ed7b52a7f811ae46fa5454e874a41464d1cb2a8 Mon Sep 17 00:00:00 2001 From: TheElementalOfDestruction Date: Fri, 8 Mar 2024 09:25:23 -0800 Subject: [PATCH 1/8] Finally fixed python version stuff for bdist_wheel --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index f7490173..1b94aef7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bdist_wheel] -universal=1 +python-tag=py3 [options.extras_require] all = From 45a87f51640189790bc0407b3e276ae35a6573ea Mon Sep 17 00:00:00 2001 From: TheElementalOfDestruction Date: Fri, 8 Mar 2024 09:48:06 -0800 Subject: [PATCH 2/8] Attempt to fix issues with asEmailMessage --- CHANGELOG.md | 3 +++ README.rst | 4 ++-- extract_msg/__init__.py | 2 +- extract_msg/msg_classes/message_base.py | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e513e208..66346a46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +**v0.48.2** +* Fixed bugs with `MessageBase.asEmailMessage()`. + **v0.48.1** * Added an option (`-s`, `--stdin`) to the command line to take an MSG file from stdin. This allows the user to pipe the MSG data from another program directly instead of having to write a middleman that uses the `extract-msg` library directly or having to write the file to the disk first. * Changed main function to allow for manual argument list to be passed to it. diff --git a/README.rst b/README.rst index e3ca5315..2d62238b 100644 --- a/README.rst +++ b/README.rst @@ -260,8 +260,8 @@ your access to the newest major version of extract-msg. .. |License: GPL v3| image:: https://img.shields.io/badge/License-GPLv3-blue.svg :target: LICENSE.txt -.. |PyPI3| image:: https://img.shields.io/badge/pypi-0.48.1-blue.svg - :target: https://pypi.org/project/extract-msg/0.48.1/ +.. |PyPI3| image:: https://img.shields.io/badge/pypi-0.48.2-blue.svg + :target: https://pypi.org/project/extract-msg/0.48.2/ .. |PyPI2| image:: https://img.shields.io/badge/python-3.8+-brightgreen.svg :target: https://www.python.org/downloads/release/python-3810/ diff --git a/extract_msg/__init__.py b/extract_msg/__init__.py index 7e3a4026..e3d9030b 100644 --- a/extract_msg/__init__.py +++ b/extract_msg/__init__.py @@ -28,7 +28,7 @@ __author__ = 'Destiny Peterson & Matthew Walker' __date__ = '2024-03-08' -__version__ = '0.48.1' +__version__ = '0.48.2' __all__ = [ # Modules: diff --git a/extract_msg/msg_classes/message_base.py b/extract_msg/msg_classes/message_base.py index 652da14e..d47086e8 100644 --- a/extract_msg/msg_classes/message_base.py +++ b/extract_msg/msg_classes/message_base.py @@ -151,7 +151,8 @@ def asEmailMessage(self) -> EmailMessage: # Copy the headers. for key, value in self.header.items(): - ret[key] = value + if key.lower() != 'content-type': + ret[key] = value.replace('\r\n', '').replace('\n', '') # Attach the body to the EmailMessage instance. if self.htmlBody: From 35a438e0fa004e732ca4eda5a3afd35bcbb9779c Mon Sep 17 00:00:00 2001 From: TheElementalOfDestruction Date: Fri, 8 Mar 2024 10:22:25 -0800 Subject: [PATCH 3/8] Fix body stuff errors for asEmailMessage --- extract_msg/msg_classes/message_base.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/extract_msg/msg_classes/message_base.py b/extract_msg/msg_classes/message_base.py index d47086e8..d42d9599 100644 --- a/extract_msg/msg_classes/message_base.py +++ b/extract_msg/msg_classes/message_base.py @@ -25,6 +25,8 @@ from email import policy from email.message import EmailMessage +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText from email.parser import HeaderParser from typing import Any, Callable, cast, Dict, List, Optional, Tuple, Type, Union @@ -155,9 +157,12 @@ def asEmailMessage(self) -> EmailMessage: ret[key] = value.replace('\r\n', '').replace('\n', '') # Attach the body to the EmailMessage instance. + bodyParts = MIMEMultipart('alternative') + ret.attach(bodyParts) if self.htmlBody: - ret.set_content(self.body, subtype = 'html', cte = 'quoted-printable') - elif self.body: + bodyParts.attach(MIMEText(self.htmlBody.decode('utf-8'), 'html')) + if self.body: + bodyParts.attach(MIMEText(self.body, 'plain')) ret.set_content(self.body, cte = 'quoted-printable') # Process attachments. From 8bce6153a123f5a8edd7c582e877e28dc65ad8ca Mon Sep 17 00:00:00 2001 From: TheElementalOfDestruction Date: Fri, 8 Mar 2024 10:46:25 -0800 Subject: [PATCH 4/8] Correctly fixed body issues --- extract_msg/msg_classes/message_base.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/extract_msg/msg_classes/message_base.py b/extract_msg/msg_classes/message_base.py index d42d9599..8ff07bed 100644 --- a/extract_msg/msg_classes/message_base.py +++ b/extract_msg/msg_classes/message_base.py @@ -24,6 +24,7 @@ import RTFDE.exceptions from email import policy +from email.charset import Charset, QP from email.message import EmailMessage from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText @@ -156,14 +157,21 @@ def asEmailMessage(self) -> EmailMessage: if key.lower() != 'content-type': ret[key] = value.replace('\r\n', '').replace('\n', '') + ret['Content-Type'] = 'multipart/mixed' + # Attach the body to the EmailMessage instance. + msgMain = MIMEMultipart('related') + ret.attach(msgMain) bodyParts = MIMEMultipart('alternative') - ret.attach(bodyParts) + msgMain.attach(bodyParts) + + c = Charset('utf-8') + c.body_encoding = QP + if self.htmlBody: - bodyParts.attach(MIMEText(self.htmlBody.decode('utf-8'), 'html')) + bodyParts.attach(MIMEText(self.htmlBody.decode('utf-8'), 'html', c)) if self.body: - bodyParts.attach(MIMEText(self.body, 'plain')) - ret.set_content(self.body, cte = 'quoted-printable') + bodyParts.attach(MIMEText(self.body, 'plain', c)) # Process attachments. for att in self.attachments: From 644870bf3d9ab3ce7e990e54fa0c0b090f350ed0 Mon Sep 17 00:00:00 2001 From: TheElementalOfDestruction Date: Fri, 8 Mar 2024 11:04:10 -0800 Subject: [PATCH 5/8] Fix attachments being attached to emailmessage wrong --- extract_msg/msg_classes/message_base.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/extract_msg/msg_classes/message_base.py b/extract_msg/msg_classes/message_base.py index 8ff07bed..b4d883fb 100644 --- a/extract_msg/msg_classes/message_base.py +++ b/extract_msg/msg_classes/message_base.py @@ -197,11 +197,15 @@ def asEmailMessage(self) -> EmailMessage: raise ConversionError(f'Could not find a suitable method to attach attachment data type "{att.dataType}".') mime = att.mimetype or 'application/octet-stream' mainType, subType = mime.split('/')[0], mime.split('/')[-1] - ret.add_attachment(data, - maintype = mainType, - subtype = subType, - filename = att.getFilename(), - cid = att.contentId) + # Need to do this manually instead of using add_attachment. + attachment = EmailMessage() + attachment.set_content(data, + maintype = mainType, + subtype = subType, + cid = att.contentId) + # This is just a very basic check. + attachment['Content-Disposition'] = f'{"inline" if att.hidden else "attachment"}; filename="{att.getFilename()}"' + ret.attach(attachment) return ret From ea58a1a4cf596a92862bc95aaa99935c1b9a59c2 Mon Sep 17 00:00:00 2001 From: TheElementalOfDestruction Date: Fri, 8 Mar 2024 14:02:46 -0800 Subject: [PATCH 6/8] Swap order of body inserting --- extract_msg/msg_classes/message_base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extract_msg/msg_classes/message_base.py b/extract_msg/msg_classes/message_base.py index b4d883fb..21d9624c 100644 --- a/extract_msg/msg_classes/message_base.py +++ b/extract_msg/msg_classes/message_base.py @@ -168,10 +168,10 @@ def asEmailMessage(self) -> EmailMessage: c = Charset('utf-8') c.body_encoding = QP - if self.htmlBody: - bodyParts.attach(MIMEText(self.htmlBody.decode('utf-8'), 'html', c)) if self.body: bodyParts.attach(MIMEText(self.body, 'plain', c)) + if self.htmlBody: + bodyParts.attach(MIMEText(self.htmlBody.decode('utf-8'), 'html', c)) # Process attachments. for att in self.attachments: From 33341bf5f57c4ab5adcabe7348c4f978a90183b5 Mon Sep 17 00:00:00 2001 From: TheElementalOfDestruction Date: Fri, 8 Mar 2024 14:55:09 -0800 Subject: [PATCH 7/8] Fix attachments not being related to body --- extract_msg/msg_classes/message_base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extract_msg/msg_classes/message_base.py b/extract_msg/msg_classes/message_base.py index 21d9624c..1f35c172 100644 --- a/extract_msg/msg_classes/message_base.py +++ b/extract_msg/msg_classes/message_base.py @@ -181,7 +181,7 @@ def asEmailMessage(self) -> EmailMessage: filename = att.getFilename() if filename.lower().endswith('.msg'): filename = filename[:-4] + '.eml' - ret.add_attachment( + msgMain.add_attachment( att.data.asEmailMessage(), filename = filename, cid = att.contentId) @@ -205,7 +205,7 @@ def asEmailMessage(self) -> EmailMessage: cid = att.contentId) # This is just a very basic check. attachment['Content-Disposition'] = f'{"inline" if att.hidden else "attachment"}; filename="{att.getFilename()}"' - ret.attach(attachment) + msgMain.attach(attachment) return ret From 20f2f76fb08e67c7efabef2936508156affe941d Mon Sep 17 00:00:00 2001 From: TheElementalOfDestruction Date: Sat, 9 Mar 2024 09:42:29 -0800 Subject: [PATCH 8/8] Cleanup for release --- CHANGELOG.md | 2 +- extract_msg/__init__.py | 2 +- extract_msg/msg_classes/message_base.py | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66346a46..781754a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ **v0.48.2** -* Fixed bugs with `MessageBase.asEmailMessage()`. +* Fixed bugs with `MessageBase.asEmailMessage()`. Numerous improvements to how it handles the data. **v0.48.1** * Added an option (`-s`, `--stdin`) to the command line to take an MSG file from stdin. This allows the user to pipe the MSG data from another program directly instead of having to write a middleman that uses the `extract-msg` library directly or having to write the file to the disk first. diff --git a/extract_msg/__init__.py b/extract_msg/__init__.py index e3d9030b..d8e2ca63 100644 --- a/extract_msg/__init__.py +++ b/extract_msg/__init__.py @@ -27,7 +27,7 @@ # along with this program. If not, see . __author__ = 'Destiny Peterson & Matthew Walker' -__date__ = '2024-03-08' +__date__ = '2024-03-09' __version__ = '0.48.2' __all__ = [ diff --git a/extract_msg/msg_classes/message_base.py b/extract_msg/msg_classes/message_base.py index 1f35c172..bfc216a7 100644 --- a/extract_msg/msg_classes/message_base.py +++ b/extract_msg/msg_classes/message_base.py @@ -205,6 +205,8 @@ def asEmailMessage(self) -> EmailMessage: cid = att.contentId) # This is just a very basic check. attachment['Content-Disposition'] = f'{"inline" if att.hidden else "attachment"}; filename="{att.getFilename()}"' + + # Add the attachment. msgMain.attach(attachment) return ret