extract-msg 0.48.0__tar.gz → 0.48.2__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.48.0 → extract_msg-0.48.2}/CHANGELOG.md +10 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/PKG-INFO +5 -4
- {extract_msg-0.48.0 → extract_msg-0.48.2}/README.rst +4 -3
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/__init__.py +2 -2
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/__main__.py +4 -3
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/attachments/attachment_base.py +47 -16
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/message_base.py +30 -10
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/utils.py +13 -2
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg.egg-info/PKG-INFO +5 -4
- {extract_msg-0.48.0 → extract_msg-0.48.2}/setup.cfg +1 -1
- {extract_msg-0.48.0 → extract_msg-0.48.2}/LICENSE.txt +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/MANIFEST.in +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/_rtf/__init__.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/_rtf/create_doc.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/_rtf/inject_rtf.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/_rtf/token.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/_rtf/tokenize_rtf.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/attachments/__init__.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/attachments/attachment.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/attachments/broken_att.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/attachments/custom_att.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/attachments/custom_att_handler/__init__.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/attachments/custom_att_handler/custom_handler.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/attachments/custom_att_handler/lnk_obj_att.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/attachments/custom_att_handler/outlook_image_dib.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/attachments/emb_msg_att.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/attachments/signed_att.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/attachments/unsupported_att.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/attachments/web_att.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/constants/__init__.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/constants/ps.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/constants/re.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/constants/st.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/data/logging-config/logging-nt.json +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/data/logging-config/logging-posix.json +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/encoding/__init__.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/encoding/_dt/__init__.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/encoding/_dt/_mac_ce.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/encoding/_dt/_mac_cyrillic.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/encoding/_dt/_mac_greek.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/encoding/_dt/_mac_iceland.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/encoding/_dt/_mac_turkish.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/encoding/_dt/_win874_dec.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/encoding/_dt/_win950_dec.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/encoding/utils.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/enums.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/exceptions.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/__init__.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/appointment.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/calendar.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/calendar_base.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/contact.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/journal.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/meeting_cancellation.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/meeting_exception.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/meeting_forward.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/meeting_related.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/meeting_request.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/meeting_response.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/message.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/message_signed.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/message_signed_base.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/msg.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/post.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/sticky_note.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/task.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/msg_classes/task_request.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/null_date.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/ole_writer.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/open_msg.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/properties/__init__.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/properties/named.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/properties/prop.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/properties/properties_store.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/py.typed +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/recipient.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/structures/__init__.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/structures/_helpers.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/structures/business_card.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/structures/cfoas.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/structures/contact_link_entry.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/structures/dev_mode_a.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/structures/dv_target_device.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/structures/entry_id.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/structures/misc_id.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/structures/mon_stream.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/structures/odt.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/structures/ole_pres.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/structures/ole_stream_struct.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/structures/recurrence_pattern.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/structures/report_tag.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/structures/system_time.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/structures/time_zone_definition.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/structures/time_zone_struct.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/structures/toc_entry.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg/structures/tz_rule.py +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg.egg-info/SOURCES.txt +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg.egg-info/dependency_links.txt +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg.egg-info/entry_points.txt +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg.egg-info/requires.txt +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/extract_msg.egg-info/top_level.txt +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/requirements.txt +0 -0
- {extract_msg-0.48.0 → extract_msg-0.48.2}/setup.py +0 -0
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
**v0.48.2**
|
|
2
|
+
* Fixed bugs with `MessageBase.asEmailMessage()`. Numerous improvements to how it handles the data.
|
|
3
|
+
|
|
4
|
+
**v0.48.1**
|
|
5
|
+
* 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.
|
|
6
|
+
* Changed main function to allow for manual argument list to be passed to it.
|
|
7
|
+
* Added attributes to `AttachmentBase` for creation and modification time. These can be accessed through `createdAt` or `creationTime` and `lastModificationTime` or `modifiedAt`.
|
|
8
|
+
* Changed `OleWriter` tests to output the name of the test file being done if an error occurs.
|
|
9
|
+
* Added tests for some command line stuff.
|
|
10
|
+
|
|
1
11
|
**v0.48.0**
|
|
2
12
|
* Adjusted error handling for named properties to handle critical streams being missing and to allow suppression of those errors.
|
|
3
13
|
* Adjusted error handling for named properties to allow silencing of errors caused by invalid references to the name stream. If `ErrorBehavior.NAMED_NAME_STREAM` is provided to the `MSGFile` instance, a warning will be logged and that entry will simply be dropped.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: extract_msg
|
|
3
|
-
Version: 0.48.
|
|
3
|
+
Version: 0.48.2
|
|
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
|
|
@@ -79,7 +79,7 @@ refer to the usage information provided from the program's help dialog:
|
|
|
79
79
|
|
|
80
80
|
usage: extract_msg [-h] [--use-content-id] [--json] [--file-logging] [-v] [--log LOG] [--config CONFIGPATH] [--out OUTPATH] [--use-filename] [--dump-stdout] [--html] [--pdf] [--wk-path WKPATH] [--wk-options [WKOPTIONS ...]]
|
|
81
81
|
[--prepared-html] [--charset CHARSET] [--raw] [--rtf] [--allow-fallback] [--skip-body-not-found] [--zip ZIP] [--save-header] [--attachments-only] [--skip-hidden] [--no-folders] [--skip-embedded] [--extract-embedded]
|
|
82
|
-
[--overwrite-existing] [--skip-not-implemented] [--out-name OUTNAME | --glob] [--ignore-rtfde] [--progress]
|
|
82
|
+
[--overwrite-existing] [--skip-not-implemented] [--out-name OUTNAME | --glob] [--ignore-rtfde] [--progress] [-s]
|
|
83
83
|
msg [msg ...]
|
|
84
84
|
|
|
85
85
|
extract_msg: Extracts emails and attachments saved in Microsoft Outlook's .msg files. https://github.com/TeamMsgExtractor/msg-extractor
|
|
@@ -125,6 +125,7 @@ refer to the usage information provided from the program's help dialog:
|
|
|
125
125
|
--glob, --wildcard Interpret all paths as having wildcards. Incompatible with --out-name.
|
|
126
126
|
--ignore-rtfde Ignores all errors thrown from RTFDE when trying to save. Useful for allowing fallback to continue when an exception happens.
|
|
127
127
|
--progress Shows what file the program is currently working on during it's progress.
|
|
128
|
+
-s, --stdin Read file from stdin (only works with one file at a time).
|
|
128
129
|
|
|
129
130
|
**To use this in your own script**, start by using:
|
|
130
131
|
|
|
@@ -277,8 +278,8 @@ your access to the newest major version of extract-msg.
|
|
|
277
278
|
.. |License: GPL v3| image:: https://img.shields.io/badge/License-GPLv3-blue.svg
|
|
278
279
|
:target: LICENSE.txt
|
|
279
280
|
|
|
280
|
-
.. |PyPI3| image:: https://img.shields.io/badge/pypi-0.48.
|
|
281
|
-
:target: https://pypi.org/project/extract-msg/0.48.
|
|
281
|
+
.. |PyPI3| image:: https://img.shields.io/badge/pypi-0.48.2-blue.svg
|
|
282
|
+
:target: https://pypi.org/project/extract-msg/0.48.2/
|
|
282
283
|
|
|
283
284
|
.. |PyPI2| image:: https://img.shields.io/badge/python-3.8+-brightgreen.svg
|
|
284
285
|
:target: https://www.python.org/downloads/release/python-3810/
|
|
@@ -61,7 +61,7 @@ refer to the usage information provided from the program's help dialog:
|
|
|
61
61
|
|
|
62
62
|
usage: extract_msg [-h] [--use-content-id] [--json] [--file-logging] [-v] [--log LOG] [--config CONFIGPATH] [--out OUTPATH] [--use-filename] [--dump-stdout] [--html] [--pdf] [--wk-path WKPATH] [--wk-options [WKOPTIONS ...]]
|
|
63
63
|
[--prepared-html] [--charset CHARSET] [--raw] [--rtf] [--allow-fallback] [--skip-body-not-found] [--zip ZIP] [--save-header] [--attachments-only] [--skip-hidden] [--no-folders] [--skip-embedded] [--extract-embedded]
|
|
64
|
-
[--overwrite-existing] [--skip-not-implemented] [--out-name OUTNAME | --glob] [--ignore-rtfde] [--progress]
|
|
64
|
+
[--overwrite-existing] [--skip-not-implemented] [--out-name OUTNAME | --glob] [--ignore-rtfde] [--progress] [-s]
|
|
65
65
|
msg [msg ...]
|
|
66
66
|
|
|
67
67
|
extract_msg: Extracts emails and attachments saved in Microsoft Outlook's .msg files. https://github.com/TeamMsgExtractor/msg-extractor
|
|
@@ -107,6 +107,7 @@ refer to the usage information provided from the program's help dialog:
|
|
|
107
107
|
--glob, --wildcard Interpret all paths as having wildcards. Incompatible with --out-name.
|
|
108
108
|
--ignore-rtfde Ignores all errors thrown from RTFDE when trying to save. Useful for allowing fallback to continue when an exception happens.
|
|
109
109
|
--progress Shows what file the program is currently working on during it's progress.
|
|
110
|
+
-s, --stdin Read file from stdin (only works with one file at a time).
|
|
110
111
|
|
|
111
112
|
**To use this in your own script**, start by using:
|
|
112
113
|
|
|
@@ -259,8 +260,8 @@ your access to the newest major version of extract-msg.
|
|
|
259
260
|
.. |License: GPL v3| image:: https://img.shields.io/badge/License-GPLv3-blue.svg
|
|
260
261
|
:target: LICENSE.txt
|
|
261
262
|
|
|
262
|
-
.. |PyPI3| image:: https://img.shields.io/badge/pypi-0.48.
|
|
263
|
-
:target: https://pypi.org/project/extract-msg/0.48.
|
|
263
|
+
.. |PyPI3| image:: https://img.shields.io/badge/pypi-0.48.2-blue.svg
|
|
264
|
+
:target: https://pypi.org/project/extract-msg/0.48.2/
|
|
264
265
|
|
|
265
266
|
.. |PyPI2| image:: https://img.shields.io/badge/python-3.8+-brightgreen.svg
|
|
266
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__ = '2024-
|
|
31
|
-
__version__ = '0.48.
|
|
30
|
+
__date__ = '2024-03-09'
|
|
31
|
+
__version__ = '0.48.2'
|
|
32
32
|
|
|
33
33
|
__all__ = [
|
|
34
34
|
# Modules:
|
|
@@ -10,12 +10,13 @@ import zipfile
|
|
|
10
10
|
|
|
11
11
|
from extract_msg import __doc__, openMsg, utils
|
|
12
12
|
from extract_msg.enums import ErrorBehavior
|
|
13
|
+
from typing import List
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
def main() -> None:
|
|
16
|
+
def main(argv : List[str]) -> None:
|
|
16
17
|
# Setup logging to stdout, indicate running from cli
|
|
17
18
|
CLI_LOGGING = 'extract_msg_cli'
|
|
18
|
-
args = utils.getCommandArgs(
|
|
19
|
+
args = utils.getCommandArgs(argv[1:])
|
|
19
20
|
|
|
20
21
|
# Determine where to save the files to.
|
|
21
22
|
currentDir = os.getcwd() # Store this in case the path changes.
|
|
@@ -111,4 +112,4 @@ def main() -> None:
|
|
|
111
112
|
_zip.close()
|
|
112
113
|
|
|
113
114
|
if __name__ == '__main__':
|
|
114
|
-
main()
|
|
115
|
+
main(sys.argv)
|
|
@@ -473,7 +473,7 @@ class AttachmentBase(abc.ABC):
|
|
|
473
473
|
the first item specifies what the second value will be.
|
|
474
474
|
"""
|
|
475
475
|
|
|
476
|
-
@
|
|
476
|
+
@cached_property
|
|
477
477
|
def attachmentEncoding(self) -> Optional[bytes]:
|
|
478
478
|
"""
|
|
479
479
|
The encoding information about the attachment object.
|
|
@@ -483,7 +483,7 @@ class AttachmentBase(abc.ABC):
|
|
|
483
483
|
"""
|
|
484
484
|
return self.getStream('__substg1.0_37020102')
|
|
485
485
|
|
|
486
|
-
@
|
|
486
|
+
@cached_property
|
|
487
487
|
def additionalInformation(self) -> Optional[str]:
|
|
488
488
|
"""
|
|
489
489
|
The additional information about the attachment.
|
|
@@ -495,7 +495,7 @@ class AttachmentBase(abc.ABC):
|
|
|
495
495
|
"""
|
|
496
496
|
return self.getStringStream('__substg1.0_370F')
|
|
497
497
|
|
|
498
|
-
@
|
|
498
|
+
@cached_property
|
|
499
499
|
def cid(self) -> Optional[str]:
|
|
500
500
|
"""
|
|
501
501
|
Returns the Content ID of the attachment, if it exists.
|
|
@@ -526,8 +526,25 @@ class AttachmentBase(abc.ABC):
|
|
|
526
526
|
|
|
527
527
|
@property
|
|
528
528
|
def contentId(self) -> Optional[str]:
|
|
529
|
+
"""
|
|
530
|
+
Alias of :attr:`cid`.
|
|
531
|
+
"""
|
|
529
532
|
return self.cid
|
|
530
533
|
|
|
534
|
+
@property
|
|
535
|
+
def createdAt(self) -> Optional[datetime.datetime]:
|
|
536
|
+
"""
|
|
537
|
+
Alias of :attr:`creationTime`.
|
|
538
|
+
"""
|
|
539
|
+
return self.creationTime
|
|
540
|
+
|
|
541
|
+
@cached_property
|
|
542
|
+
def creationTime(self) -> Optional[datetime.datetime]:
|
|
543
|
+
"""
|
|
544
|
+
The time the attachment was created.
|
|
545
|
+
"""
|
|
546
|
+
return self.getPropertyVal('30070040')
|
|
547
|
+
|
|
531
548
|
@property
|
|
532
549
|
@abc.abstractmethod
|
|
533
550
|
def data(self) -> Optional[object]:
|
|
@@ -537,7 +554,7 @@ class AttachmentBase(abc.ABC):
|
|
|
537
554
|
Returns ``None`` if there is no data to save.
|
|
538
555
|
"""
|
|
539
556
|
|
|
540
|
-
@
|
|
557
|
+
@cached_property
|
|
541
558
|
def dataType(self) -> Optional[Type[object]]:
|
|
542
559
|
"""
|
|
543
560
|
The class that the data type will use, if it can be retrieved.
|
|
@@ -560,14 +577,14 @@ class AttachmentBase(abc.ABC):
|
|
|
560
577
|
"""
|
|
561
578
|
return self.__dir
|
|
562
579
|
|
|
563
|
-
@
|
|
580
|
+
@cached_property
|
|
564
581
|
def displayName(self) -> Optional[str]:
|
|
565
582
|
"""
|
|
566
583
|
Returns the display name of the folder.
|
|
567
584
|
"""
|
|
568
585
|
return self.getStringStream('__substg1.0_3001')
|
|
569
586
|
|
|
570
|
-
@
|
|
587
|
+
@cached_property
|
|
571
588
|
def exceptionReplaceTime(self) -> Optional[datetime.datetime]:
|
|
572
589
|
"""
|
|
573
590
|
The original date and time at which the instance in the recurrence
|
|
@@ -577,48 +594,62 @@ class AttachmentBase(abc.ABC):
|
|
|
577
594
|
"""
|
|
578
595
|
return self.getPropertyVal('7FF90040')
|
|
579
596
|
|
|
580
|
-
@
|
|
597
|
+
@cached_property
|
|
581
598
|
def extension(self) -> Optional[str]:
|
|
582
599
|
"""
|
|
583
600
|
The reported extension for the file.
|
|
584
601
|
"""
|
|
585
602
|
return self.getStringStream('__substg1.0_3703')
|
|
586
603
|
|
|
587
|
-
@
|
|
604
|
+
@cached_property
|
|
588
605
|
def hidden(self) -> bool:
|
|
589
606
|
"""
|
|
590
607
|
Indicates whether an Attachment object is hidden from the end user.
|
|
591
608
|
"""
|
|
592
609
|
return bool(self.getPropertyVal('7FFE000B'))
|
|
593
610
|
|
|
594
|
-
@
|
|
611
|
+
@cached_property
|
|
595
612
|
def isAttachmentContactPhoto(self) -> bool:
|
|
596
613
|
"""
|
|
597
614
|
Whether the attachment is a contact photo for a Contact object.
|
|
598
615
|
"""
|
|
599
616
|
return bool(self.getPropertyVal('7FFF000B'))
|
|
600
617
|
|
|
601
|
-
@
|
|
618
|
+
@cached_property
|
|
619
|
+
def lastModificationTime(self) -> Optional[datetime.datetime]:
|
|
620
|
+
"""
|
|
621
|
+
The last time the attachment was modified.
|
|
622
|
+
"""
|
|
623
|
+
return self.getPropertyVal('30080040')
|
|
624
|
+
|
|
625
|
+
@cached_property
|
|
602
626
|
def longFilename(self) -> Optional[str]:
|
|
603
627
|
"""
|
|
604
628
|
Returns the long file name of the attachment, if it exists.
|
|
605
629
|
"""
|
|
606
630
|
return self.getStringStream('__substg1.0_3707')
|
|
607
631
|
|
|
608
|
-
@
|
|
632
|
+
@cached_property
|
|
609
633
|
def longPathname(self) -> Optional[str]:
|
|
610
634
|
"""
|
|
611
635
|
The fully qualified path and file name with extension.
|
|
612
636
|
"""
|
|
613
637
|
return self.getStringStream('__substg1.0_370D')
|
|
614
638
|
|
|
615
|
-
@
|
|
639
|
+
@cached_property
|
|
616
640
|
def mimetype(self) -> Optional[str]:
|
|
617
641
|
"""
|
|
618
642
|
The content-type mime header of the attachment, if specified.
|
|
619
643
|
"""
|
|
620
644
|
return tryGetMimetype(self, self.getStringStream('__substg1.0_370E'))
|
|
621
645
|
|
|
646
|
+
@property
|
|
647
|
+
def modifiedAt(self) -> Optional[datetime.datetime]:
|
|
648
|
+
"""
|
|
649
|
+
Alias of :attr:`lastModificationTime`.
|
|
650
|
+
"""
|
|
651
|
+
return self.lastModificationTime
|
|
652
|
+
|
|
622
653
|
@property
|
|
623
654
|
def msg(self) -> MSGFile:
|
|
624
655
|
"""
|
|
@@ -631,7 +662,7 @@ class AttachmentBase(abc.ABC):
|
|
|
631
662
|
raise ReferenceError('The MSGFile for this Attachment instance has been garbage collected.')
|
|
632
663
|
return msg
|
|
633
664
|
|
|
634
|
-
@
|
|
665
|
+
@cached_property
|
|
635
666
|
def name(self) -> Optional[str]:
|
|
636
667
|
"""
|
|
637
668
|
The best name available for the file.
|
|
@@ -650,7 +681,7 @@ class AttachmentBase(abc.ABC):
|
|
|
650
681
|
"""
|
|
651
682
|
return self.__namedProperties
|
|
652
683
|
|
|
653
|
-
@
|
|
684
|
+
@cached_property
|
|
654
685
|
def payloadClass(self) -> Optional[str]:
|
|
655
686
|
"""
|
|
656
687
|
The class name of an object that can display the contents of the
|
|
@@ -665,7 +696,7 @@ class AttachmentBase(abc.ABC):
|
|
|
665
696
|
"""
|
|
666
697
|
return self.__props
|
|
667
698
|
|
|
668
|
-
@
|
|
699
|
+
@cached_property
|
|
669
700
|
def renderingPosition(self) -> Optional[int]:
|
|
670
701
|
"""
|
|
671
702
|
The offset, in rendered characters, to use when rendering the attachment
|
|
@@ -676,7 +707,7 @@ class AttachmentBase(abc.ABC):
|
|
|
676
707
|
"""
|
|
677
708
|
return self.getPropertyVal('370B0003')
|
|
678
709
|
|
|
679
|
-
@
|
|
710
|
+
@cached_property
|
|
680
711
|
def shortFilename(self) -> Optional[str]:
|
|
681
712
|
"""
|
|
682
713
|
The short file name of the attachment, if it exists.
|
|
@@ -24,7 +24,10 @@ import RTFDE
|
|
|
24
24
|
import RTFDE.exceptions
|
|
25
25
|
|
|
26
26
|
from email import policy
|
|
27
|
+
from email.charset import Charset, QP
|
|
27
28
|
from email.message import EmailMessage
|
|
29
|
+
from email.mime.multipart import MIMEMultipart
|
|
30
|
+
from email.mime.text import MIMEText
|
|
28
31
|
from email.parser import HeaderParser
|
|
29
32
|
from typing import Any, Callable, cast, Dict, List, Optional, Tuple, Type, Union
|
|
30
33
|
|
|
@@ -151,13 +154,24 @@ class MessageBase(MSGFile):
|
|
|
151
154
|
|
|
152
155
|
# Copy the headers.
|
|
153
156
|
for key, value in self.header.items():
|
|
154
|
-
|
|
157
|
+
if key.lower() != 'content-type':
|
|
158
|
+
ret[key] = value.replace('\r\n', '').replace('\n', '')
|
|
159
|
+
|
|
160
|
+
ret['Content-Type'] = 'multipart/mixed'
|
|
155
161
|
|
|
156
162
|
# Attach the body to the EmailMessage instance.
|
|
163
|
+
msgMain = MIMEMultipart('related')
|
|
164
|
+
ret.attach(msgMain)
|
|
165
|
+
bodyParts = MIMEMultipart('alternative')
|
|
166
|
+
msgMain.attach(bodyParts)
|
|
167
|
+
|
|
168
|
+
c = Charset('utf-8')
|
|
169
|
+
c.body_encoding = QP
|
|
170
|
+
|
|
171
|
+
if self.body:
|
|
172
|
+
bodyParts.attach(MIMEText(self.body, 'plain', c))
|
|
157
173
|
if self.htmlBody:
|
|
158
|
-
|
|
159
|
-
elif self.body:
|
|
160
|
-
ret.set_content(self.body, cte = 'quoted-printable')
|
|
174
|
+
bodyParts.attach(MIMEText(self.htmlBody.decode('utf-8'), 'html', c))
|
|
161
175
|
|
|
162
176
|
# Process attachments.
|
|
163
177
|
for att in self.attachments:
|
|
@@ -167,7 +181,7 @@ class MessageBase(MSGFile):
|
|
|
167
181
|
filename = att.getFilename()
|
|
168
182
|
if filename.lower().endswith('.msg'):
|
|
169
183
|
filename = filename[:-4] + '.eml'
|
|
170
|
-
|
|
184
|
+
msgMain.add_attachment(
|
|
171
185
|
att.data.asEmailMessage(),
|
|
172
186
|
filename = filename,
|
|
173
187
|
cid = att.contentId)
|
|
@@ -183,11 +197,17 @@ class MessageBase(MSGFile):
|
|
|
183
197
|
raise ConversionError(f'Could not find a suitable method to attach attachment data type "{att.dataType}".')
|
|
184
198
|
mime = att.mimetype or 'application/octet-stream'
|
|
185
199
|
mainType, subType = mime.split('/')[0], mime.split('/')[-1]
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
200
|
+
# Need to do this manually instead of using add_attachment.
|
|
201
|
+
attachment = EmailMessage()
|
|
202
|
+
attachment.set_content(data,
|
|
203
|
+
maintype = mainType,
|
|
204
|
+
subtype = subType,
|
|
205
|
+
cid = att.contentId)
|
|
206
|
+
# This is just a very basic check.
|
|
207
|
+
attachment['Content-Disposition'] = f'{"inline" if att.hidden else "attachment"}; filename="{att.getFilename()}"'
|
|
208
|
+
|
|
209
|
+
# Add the attachment.
|
|
210
|
+
msgMain.attach(attachment)
|
|
191
211
|
|
|
192
212
|
return ret
|
|
193
213
|
|
|
@@ -63,6 +63,7 @@ import os
|
|
|
63
63
|
import pathlib
|
|
64
64
|
import shutil
|
|
65
65
|
import struct
|
|
66
|
+
import sys
|
|
66
67
|
import weakref
|
|
67
68
|
import zipfile
|
|
68
69
|
|
|
@@ -359,6 +360,7 @@ def getCommandArgs(args: Sequence[str]) -> argparse.Namespace:
|
|
|
359
360
|
parser = argparse.ArgumentParser(description = constants.MAINDOC, prog = 'extract_msg')
|
|
360
361
|
outFormat = parser.add_mutually_exclusive_group()
|
|
361
362
|
inputFormat = parser.add_mutually_exclusive_group()
|
|
363
|
+
inputType = parser.add_mutually_exclusive_group(required = True)
|
|
362
364
|
# --use-content-id, --cid
|
|
363
365
|
parser.add_argument('--use-content-id', '--cid', dest='cid', action='store_true',
|
|
364
366
|
help='Save attachments by their Content ID, if they have one. Useful when working with the HTML body.')
|
|
@@ -368,7 +370,7 @@ def getCommandArgs(args: Sequence[str]) -> argparse.Namespace:
|
|
|
368
370
|
# --file-logging
|
|
369
371
|
parser.add_argument('--file-logging', dest='fileLogging', action='store_true',
|
|
370
372
|
help='Enables file logging. Implies --verbose level 1.')
|
|
371
|
-
# --verbose
|
|
373
|
+
# -v, --verbose
|
|
372
374
|
parser.add_argument('-v', '--verbose', dest='verbose', action='count', default=0,
|
|
373
375
|
help='Turns on console logging. Specify more than once for higher verbosity.')
|
|
374
376
|
# --log PATH
|
|
@@ -455,12 +457,19 @@ def getCommandArgs(args: Sequence[str]) -> argparse.Namespace:
|
|
|
455
457
|
# --progress
|
|
456
458
|
parser.add_argument('--progress', dest='progress', action='store_true',
|
|
457
459
|
help='Shows what file the program is currently working on during it\'s progress.')
|
|
460
|
+
# -s, --stdout
|
|
461
|
+
inputType.add_argument('-s', '--stdin', dest='stdin', action='store_true',
|
|
462
|
+
help='Read file from stdin (only works with one file at a time).')
|
|
458
463
|
# [MSG files]
|
|
459
|
-
|
|
464
|
+
inputType.add_argument('msgs', metavar='msg', nargs='*', default=[],
|
|
460
465
|
help='An MSG file to be parsed.')
|
|
461
466
|
|
|
462
467
|
options = parser.parse_args(args)
|
|
463
468
|
|
|
469
|
+
if options.stdin:
|
|
470
|
+
# Read the MSG file from stdin and shove it into the msgs list.
|
|
471
|
+
options.msgs.append(sys.stdin.buffer.read())
|
|
472
|
+
|
|
464
473
|
if options.outName and options.noFolders:
|
|
465
474
|
raise IncompatibleOptionsError('--out-name is not compatible with --no-folders.')
|
|
466
475
|
|
|
@@ -502,6 +511,8 @@ def getCommandArgs(args: Sequence[str]) -> argparse.Namespace:
|
|
|
502
511
|
if options.glob:
|
|
503
512
|
if options.outName:
|
|
504
513
|
raise IncompatibleOptionsError('--out-name is not supported when using wildcards.')
|
|
514
|
+
if options.stdin:
|
|
515
|
+
raise IncompatibleOptionsError('--stdin is not supported with using wildcards.')
|
|
505
516
|
fileLists = []
|
|
506
517
|
for path in options.msgs:
|
|
507
518
|
fileLists += glob.glob(path)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: extract-msg
|
|
3
|
-
Version: 0.48.
|
|
3
|
+
Version: 0.48.2
|
|
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
|
|
@@ -79,7 +79,7 @@ refer to the usage information provided from the program's help dialog:
|
|
|
79
79
|
|
|
80
80
|
usage: extract_msg [-h] [--use-content-id] [--json] [--file-logging] [-v] [--log LOG] [--config CONFIGPATH] [--out OUTPATH] [--use-filename] [--dump-stdout] [--html] [--pdf] [--wk-path WKPATH] [--wk-options [WKOPTIONS ...]]
|
|
81
81
|
[--prepared-html] [--charset CHARSET] [--raw] [--rtf] [--allow-fallback] [--skip-body-not-found] [--zip ZIP] [--save-header] [--attachments-only] [--skip-hidden] [--no-folders] [--skip-embedded] [--extract-embedded]
|
|
82
|
-
[--overwrite-existing] [--skip-not-implemented] [--out-name OUTNAME | --glob] [--ignore-rtfde] [--progress]
|
|
82
|
+
[--overwrite-existing] [--skip-not-implemented] [--out-name OUTNAME | --glob] [--ignore-rtfde] [--progress] [-s]
|
|
83
83
|
msg [msg ...]
|
|
84
84
|
|
|
85
85
|
extract_msg: Extracts emails and attachments saved in Microsoft Outlook's .msg files. https://github.com/TeamMsgExtractor/msg-extractor
|
|
@@ -125,6 +125,7 @@ refer to the usage information provided from the program's help dialog:
|
|
|
125
125
|
--glob, --wildcard Interpret all paths as having wildcards. Incompatible with --out-name.
|
|
126
126
|
--ignore-rtfde Ignores all errors thrown from RTFDE when trying to save. Useful for allowing fallback to continue when an exception happens.
|
|
127
127
|
--progress Shows what file the program is currently working on during it's progress.
|
|
128
|
+
-s, --stdin Read file from stdin (only works with one file at a time).
|
|
128
129
|
|
|
129
130
|
**To use this in your own script**, start by using:
|
|
130
131
|
|
|
@@ -277,8 +278,8 @@ your access to the newest major version of extract-msg.
|
|
|
277
278
|
.. |License: GPL v3| image:: https://img.shields.io/badge/License-GPLv3-blue.svg
|
|
278
279
|
:target: LICENSE.txt
|
|
279
280
|
|
|
280
|
-
.. |PyPI3| image:: https://img.shields.io/badge/pypi-0.48.
|
|
281
|
-
:target: https://pypi.org/project/extract-msg/0.48.
|
|
281
|
+
.. |PyPI3| image:: https://img.shields.io/badge/pypi-0.48.2-blue.svg
|
|
282
|
+
:target: https://pypi.org/project/extract-msg/0.48.2/
|
|
282
283
|
|
|
283
284
|
.. |PyPI2| image:: https://img.shields.io/badge/python-3.8+-brightgreen.svg
|
|
284
285
|
:target: https://www.python.org/downloads/release/python-3810/
|
|
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.48.0 → extract_msg-0.48.2}/extract_msg/attachments/custom_att_handler/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{extract_msg-0.48.0 → extract_msg-0.48.2}/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
|
{extract_msg-0.48.0 → extract_msg-0.48.2}/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
|