extract-msg 0.55.0__tar.gz → 0.56.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {extract_msg-0.55.0 → extract_msg-0.56.0}/CHANGELOG.md +7 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/PKG-INFO +3 -3
- {extract_msg-0.55.0 → extract_msg-0.56.0}/README.rst +2 -2
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/__init__.py +2 -2
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/message_base.py +117 -7
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg.egg-info/PKG-INFO +3 -3
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg.egg-info/requires.txt +2 -2
- {extract_msg-0.55.0 → extract_msg-0.56.0}/requirements.txt +4 -2
- {extract_msg-0.55.0 → extract_msg-0.56.0}/LICENSE.txt +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/MANIFEST.in +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/__main__.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/_rtf/__init__.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/_rtf/create_doc.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/_rtf/inject_rtf.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/_rtf/token.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/_rtf/tokenize_rtf.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/attachments/__init__.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/attachments/attachment.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/attachments/attachment_base.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/attachments/broken_att.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/attachments/custom_att.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/attachments/custom_att_handler/__init__.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/attachments/custom_att_handler/custom_handler.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/attachments/custom_att_handler/lnk_obj_att.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/attachments/custom_att_handler/outlook_image_dib.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/attachments/custom_att_handler/outlook_image_meta.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/attachments/emb_msg_att.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/attachments/signed_att.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/attachments/unsupported_att.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/attachments/web_att.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/constants/__init__.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/constants/ps.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/constants/re.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/constants/st.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/data/logging-config/logging-nt.json +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/data/logging-config/logging-posix.json +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/encoding/__init__.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/encoding/_dt/__init__.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/encoding/_dt/_mac_ce.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/encoding/_dt/_mac_cyrillic.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/encoding/_dt/_mac_greek.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/encoding/_dt/_mac_iceland.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/encoding/_dt/_mac_turkish.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/encoding/_dt/_win874_dec.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/encoding/_dt/_win950_dec.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/encoding/utils.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/enums.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/exceptions.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/__init__.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/appointment.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/calendar.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/calendar_base.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/contact.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/journal.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/meeting_cancellation.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/meeting_exception.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/meeting_forward.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/meeting_related.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/meeting_request.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/meeting_response.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/message.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/message_signed.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/message_signed_base.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/msg.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/post.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/sticky_note.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/task.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/msg_classes/task_request.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/null_date.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/ole_writer.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/open_msg.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/properties/__init__.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/properties/named.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/properties/prop.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/properties/properties_store.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/py.typed +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/recipient.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/structures/__init__.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/structures/_helpers.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/structures/business_card.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/structures/cfoas.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/structures/contact_link_entry.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/structures/dev_mode_a.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/structures/dv_target_device.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/structures/entry_id.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/structures/misc_id.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/structures/mon_stream.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/structures/odt.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/structures/ole_pres.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/structures/ole_stream_struct.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/structures/recurrence_pattern.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/structures/report_tag.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/structures/system_time.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/structures/time_zone_definition.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/structures/time_zone_struct.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/structures/toc_entry.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/structures/tz_rule.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/utils.py +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg.egg-info/SOURCES.txt +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg.egg-info/dependency_links.txt +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg.egg-info/entry_points.txt +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg.egg-info/top_level.txt +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/setup.cfg +0 -0
- {extract_msg-0.55.0 → extract_msg-0.56.0}/setup.py +0 -0
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
**v0.56.0**
|
|
2
|
+
* [[TeamMsgExtractor #478](https://github.com/TeamMsgExtractor/msg-extractor/issues/478)] Expand allowable versions of `ebcdic` to include `2.x`. The 2.0 release is a pure technical release with no functional changes; it only drops support for Python 2 and 3.8. The lower bound is unchanged so installs on Python 3.8 will continue to resolve to `ebcdic 1.1.1`.
|
|
3
|
+
* [[TeamMsgExtractor #469](https://github.com/TeamMsgExtractor/msg-extractor/issues/469)] Expanded `beautifulsoup` to allow for versions up to `5.*.*`. I was previously hesitant to do so because they sometimes do what seems like non backwards compatible changes in minor versions, but it looks like this should be fine.
|
|
4
|
+
* [[TeamMsgExtractor #471](https://github.com/TeamMsgExtractor/msg-extractor/issues/471)] Added `.strip()` to file name determination to ensure that folders with trailing spaces would be corrected before being used.
|
|
5
|
+
* [[TeamMsgExtractor #481](https://github.com/TeamMsgExtractor/msg-extractor/issues/481)] Fixed a typo that caused an HTML body created from plain text to end with `</head>` instead of `</html>`.
|
|
6
|
+
* [[TeamMsgExtractor #476](https://github.com/TeamMsgExtractor/msg-extractor/issues/476)] Fixed `MessageBase.asEmailMessage()` raising `ValueError` when a message has multiple `To` recipients.
|
|
7
|
+
|
|
1
8
|
**v0.55.0**
|
|
2
9
|
* [[TeamMsgExtractor #465](https://github.com/TeamMsgExtractor/msg-extractor/issues/465)] Added missing `msg.close()` to `openMsg()`. If the MSG file was actually just a plain OLE file, it would be left open.
|
|
3
10
|
* Adjusted the default value of `maxNameLength` for `MessageBase.save()` to 40 instead of 256.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: extract_msg
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.56.0
|
|
4
4
|
Summary: Extracts emails and attachments saved in Microsoft Outlook's .msg files
|
|
5
5
|
Home-page: https://github.com/TeamMsgExtractor/msg-extractor
|
|
6
6
|
Download-URL: https://github.com/TeamMsgExtractor/msg-extractor/archives/master
|
|
@@ -278,8 +278,8 @@ your access to the newest major version of extract-msg.
|
|
|
278
278
|
.. |License: GPL v3| image:: https://img.shields.io/badge/License-GPLv3-blue.svg
|
|
279
279
|
:target: LICENSE.txt
|
|
280
280
|
|
|
281
|
-
.. |PyPI3| image:: https://img.shields.io/badge/pypi-0.
|
|
282
|
-
:target: https://pypi.org/project/extract-msg/0.
|
|
281
|
+
.. |PyPI3| image:: https://img.shields.io/badge/pypi-0.56.0-blue.svg
|
|
282
|
+
:target: https://pypi.org/project/extract-msg/0.56.0/
|
|
283
283
|
|
|
284
284
|
.. |PyPI2| image:: https://img.shields.io/badge/python-3.8+-brightgreen.svg
|
|
285
285
|
:target: https://www.python.org/downloads/release/python-3810/
|
|
@@ -260,8 +260,8 @@ your access to the newest major version of extract-msg.
|
|
|
260
260
|
.. |License: GPL v3| image:: https://img.shields.io/badge/License-GPLv3-blue.svg
|
|
261
261
|
:target: LICENSE.txt
|
|
262
262
|
|
|
263
|
-
.. |PyPI3| image:: https://img.shields.io/badge/pypi-0.
|
|
264
|
-
:target: https://pypi.org/project/extract-msg/0.
|
|
263
|
+
.. |PyPI3| image:: https://img.shields.io/badge/pypi-0.56.0-blue.svg
|
|
264
|
+
:target: https://pypi.org/project/extract-msg/0.56.0/
|
|
265
265
|
|
|
266
266
|
.. |PyPI2| image:: https://img.shields.io/badge/python-3.8+-brightgreen.svg
|
|
267
267
|
:target: https://www.python.org/downloads/release/python-3810/
|
|
@@ -27,8 +27,8 @@ https://github.com/TeamMsgExtractor/msg-extractor
|
|
|
27
27
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
28
28
|
|
|
29
29
|
__author__ = 'Destiny Peterson & Matthew Walker'
|
|
30
|
-
__date__ = '
|
|
31
|
-
__version__ = '0.
|
|
30
|
+
__date__ = '2026-07-18'
|
|
31
|
+
__version__ = '0.56.0'
|
|
32
32
|
|
|
33
33
|
__all__ = [
|
|
34
34
|
# Modules:
|
|
@@ -25,6 +25,7 @@ import RTFDE.exceptions
|
|
|
25
25
|
|
|
26
26
|
from email import policy
|
|
27
27
|
from email.charset import Charset, QP
|
|
28
|
+
from email.header import decode_header as _decode_header, Header as _Header
|
|
28
29
|
from email.message import EmailMessage
|
|
29
30
|
from email.mime.multipart import MIMEMultipart
|
|
30
31
|
from email.mime.text import MIMEText
|
|
@@ -56,6 +57,77 @@ from ..utils import (
|
|
|
56
57
|
logger = logging.getLogger(__name__)
|
|
57
58
|
logger.addHandler(logging.NullHandler())
|
|
58
59
|
|
|
60
|
+
_RFC2047_WORD = re.compile(r'=\?[^?]+\?[bBqQ]\?[^?]*\?=')
|
|
61
|
+
|
|
62
|
+
# Encodings to try when a declared charset fails, keyed by normalised charset name.
|
|
63
|
+
# GBK is a strict superset of GB2312 and accepts the ASCII-range second bytes that
|
|
64
|
+
# GB2312 rejects, so real-world GB2312-labelled headers often decode correctly as GBK.
|
|
65
|
+
_CHARSET_FALLBACKS: Dict[str, Tuple[str, ...]] = {
|
|
66
|
+
'gb2312': ('gbk', 'cp936'),
|
|
67
|
+
'gb_2312': ('gbk', 'cp936'),
|
|
68
|
+
'gb_2312-80': ('gbk', 'cp936'),
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _fix_encoded_word(m: re.Match) -> str:
|
|
73
|
+
"""
|
|
74
|
+
Regex substitution callback: decode one RFC 2047 encoded word and
|
|
75
|
+
re-emit it as a valid UTF-8 encoded word.
|
|
76
|
+
|
|
77
|
+
If the declared charset fails (e.g. GB2312-labelled GBK bytes), charset
|
|
78
|
+
fallbacks from _CHARSET_FALLBACKS are tried before falling back to
|
|
79
|
+
latin-1 with replacement characters.
|
|
80
|
+
"""
|
|
81
|
+
word = m.group(0)
|
|
82
|
+
try:
|
|
83
|
+
parts = _decode_header(word)
|
|
84
|
+
if len(parts) != 1 or not isinstance(parts[0][0], bytes):
|
|
85
|
+
return word
|
|
86
|
+
btext, cs = parts[0]
|
|
87
|
+
try:
|
|
88
|
+
text = btext.decode(cs or 'ascii')
|
|
89
|
+
except (UnicodeDecodeError, LookupError):
|
|
90
|
+
for fallback in _CHARSET_FALLBACKS.get((cs or '').lower(), ()):
|
|
91
|
+
try:
|
|
92
|
+
text = btext.decode(fallback)
|
|
93
|
+
break
|
|
94
|
+
except (UnicodeDecodeError, LookupError):
|
|
95
|
+
continue
|
|
96
|
+
else:
|
|
97
|
+
text = btext.decode('latin-1', 'replace')
|
|
98
|
+
return str(_Header(text, charset='utf-8'))
|
|
99
|
+
except Exception:
|
|
100
|
+
return word
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _preprocess_encoded_words(text: str) -> str:
|
|
104
|
+
"""
|
|
105
|
+
Replace every RFC 2047 encoded word in *text* with a clean UTF-8
|
|
106
|
+
encoded word. Safe to apply to an entire raw header block before
|
|
107
|
+
feeding it to the modern email policy parser.
|
|
108
|
+
"""
|
|
109
|
+
return _RFC2047_WORD.sub(_fix_encoded_word, text)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _sanitize_header(value: str) -> str:
|
|
113
|
+
"""
|
|
114
|
+
Prepare a header value from a compat32-parsed Message for safe assignment
|
|
115
|
+
to an EmailMessage (fallback path when no raw headerText is available).
|
|
116
|
+
|
|
117
|
+
RFC 2047 encoded words are re-encoded as UTF-8; raw non-ASCII characters
|
|
118
|
+
are also RFC 2047-encoded so that EmailMessage.as_bytes() never raises
|
|
119
|
+
UnicodeEncodeError.
|
|
120
|
+
"""
|
|
121
|
+
if '=?' in value:
|
|
122
|
+
value = _RFC2047_WORD.sub(_fix_encoded_word, value)
|
|
123
|
+
|
|
124
|
+
try:
|
|
125
|
+
value.encode('ascii')
|
|
126
|
+
except (UnicodeEncodeError, UnicodeDecodeError):
|
|
127
|
+
value = str(_Header(value, charset='utf-8'))
|
|
128
|
+
|
|
129
|
+
return value
|
|
130
|
+
|
|
59
131
|
|
|
60
132
|
class MessageBase(MSGFile):
|
|
61
133
|
"""
|
|
@@ -165,10 +237,48 @@ class MessageBase(MSGFile):
|
|
|
165
237
|
"""
|
|
166
238
|
ret = EmailMessage()
|
|
167
239
|
|
|
168
|
-
#
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
240
|
+
# Prefer the raw transport-header block: pre-fix any malformed RFC 2047
|
|
241
|
+
# encoded words (e.g. GB2312-labelled GBK bytes), then parse with the
|
|
242
|
+
# modern policy so that RFC 5322 unfolding and RFC 2047 decoding are
|
|
243
|
+
# handled natively and the values arrive as clean Unicode strings.
|
|
244
|
+
# Fall back to the compat32-derived self.header when no raw text is
|
|
245
|
+
# stored (synthesised headers from MAPI properties).
|
|
246
|
+
_ADDRESS_HEADERS = frozenset({'to', 'cc', 'bcc', 'reply-to'})
|
|
247
|
+
if self.headerText:
|
|
248
|
+
raw = self.headerText
|
|
249
|
+
if raw.startswith('Microsoft Mail Internet Headers Version 2.0'):
|
|
250
|
+
raw = raw[43:].lstrip()
|
|
251
|
+
raw = _preprocess_encoded_words(raw)
|
|
252
|
+
source_items = list(HeaderParser(policy = policy.default).parsestr(raw).items())
|
|
253
|
+
sanitize = False
|
|
254
|
+
else:
|
|
255
|
+
source_items = list(self.header.items())
|
|
256
|
+
sanitize = True
|
|
257
|
+
|
|
258
|
+
# Address headers (To/CC/BCC/Reply-To) may appear once per recipient in
|
|
259
|
+
# the stored header block; merge them into a single comma-separated value.
|
|
260
|
+
# All other headers — including multi-valued trace headers like Received
|
|
261
|
+
# and Authentication-Results — are forwarded as-is; EmailMessage appends
|
|
262
|
+
# rather than replaces, so natural repetition is preserved correctly.
|
|
263
|
+
address_merged: Dict[str, Tuple[str, str]] = {}
|
|
264
|
+
for key, value in source_items:
|
|
265
|
+
if key.lower() == 'content-type':
|
|
266
|
+
continue
|
|
267
|
+
if sanitize:
|
|
268
|
+
# compat32 values are folded and may contain raw encoded words.
|
|
269
|
+
value = re.sub(r'\r?\n[ \t]', ' ', value)
|
|
270
|
+
value = value.replace('\r\n', '').replace('\n', '')
|
|
271
|
+
value = _sanitize_header(value)
|
|
272
|
+
lower = key.lower()
|
|
273
|
+
if lower in _ADDRESS_HEADERS:
|
|
274
|
+
if lower in address_merged:
|
|
275
|
+
address_merged[lower] = (address_merged[lower][0], address_merged[lower][1] + ', ' + value)
|
|
276
|
+
else:
|
|
277
|
+
address_merged[lower] = (key, value)
|
|
278
|
+
else:
|
|
279
|
+
ret[key] = value
|
|
280
|
+
for _, (key, value) in address_merged.items():
|
|
281
|
+
ret[key] = value
|
|
172
282
|
|
|
173
283
|
ret['Content-Type'] = 'multipart/mixed'
|
|
174
284
|
|
|
@@ -855,9 +965,9 @@ class MessageBase(MSGFile):
|
|
|
855
965
|
raise ValueError(f'Invalid filename found in self.filename: "{self.filename}"')
|
|
856
966
|
|
|
857
967
|
# Add the file name to the path.
|
|
858
|
-
path /= filename[:maxNameLength]
|
|
968
|
+
path /= filename[:maxNameLength].strip()
|
|
859
969
|
else:
|
|
860
|
-
path /= self.defaultFolderName[:maxNameLength]
|
|
970
|
+
path /= self.defaultFolderName[:maxNameLength].strip()
|
|
861
971
|
|
|
862
972
|
# Create the folders.
|
|
863
973
|
if not _zip:
|
|
@@ -1178,7 +1288,7 @@ class MessageBase(MSGFile):
|
|
|
1178
1288
|
# Convert the plain text body to html.
|
|
1179
1289
|
logger.info('HTML body was not found, attempting to generate from plain text body.')
|
|
1180
1290
|
correctedBody = html.escape(self.body).replace('\r', '').replace('\n', '<br />')
|
|
1181
|
-
htmlBody = f'<html><body>{correctedBody}</body></
|
|
1291
|
+
htmlBody = f'<html><body>{correctedBody}</body></html>'.encode('ascii', 'xmlcharrefreplace')
|
|
1182
1292
|
|
|
1183
1293
|
if not htmlBody:
|
|
1184
1294
|
logger.info('HTML body could not be found nor generated.')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: extract-msg
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.56.0
|
|
4
4
|
Summary: Extracts emails and attachments saved in Microsoft Outlook's .msg files
|
|
5
5
|
Home-page: https://github.com/TeamMsgExtractor/msg-extractor
|
|
6
6
|
Download-URL: https://github.com/TeamMsgExtractor/msg-extractor/archives/master
|
|
@@ -278,8 +278,8 @@ your access to the newest major version of extract-msg.
|
|
|
278
278
|
.. |License: GPL v3| image:: https://img.shields.io/badge/License-GPLv3-blue.svg
|
|
279
279
|
:target: LICENSE.txt
|
|
280
280
|
|
|
281
|
-
.. |PyPI3| image:: https://img.shields.io/badge/pypi-0.
|
|
282
|
-
:target: https://pypi.org/project/extract-msg/0.
|
|
281
|
+
.. |PyPI3| image:: https://img.shields.io/badge/pypi-0.56.0-blue.svg
|
|
282
|
+
:target: https://pypi.org/project/extract-msg/0.56.0/
|
|
283
283
|
|
|
284
284
|
.. |PyPI2| image:: https://img.shields.io/badge/python-3.8+-brightgreen.svg
|
|
285
285
|
:target: https://www.python.org/downloads/release/python-3810/
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
olefile==0.47
|
|
6
6
|
tzlocal>=4.2,<6
|
|
7
7
|
compressed-rtf>=1.0.6,<2
|
|
8
|
-
ebcdic>=1.1.1,<
|
|
9
|
-
|
|
8
|
+
ebcdic>=1.1.1,<3
|
|
9
|
+
# Beautiful soup can sometimes make weird versioning, so something *could*
|
|
10
|
+
# break, but so long as they at least reasonably do sem-var this should be fine.
|
|
11
|
+
beautifulsoup4>=4.11.1,<5
|
|
10
12
|
RTFDE>=0.1.1,<0.2
|
|
11
13
|
red-black-tree-mod>=1.20, <=1.23
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/attachments/custom_att_handler/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/attachments/custom_att_handler/lnk_obj_att.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{extract_msg-0.55.0 → extract_msg-0.56.0}/extract_msg/data/logging-config/logging-posix.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|