NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #1653 most downloaded on PyPI
Extracts emails and attachments saved in Microsoft Outlook's .msg files
Last release 1 months ago
14 Aug 2026
Release timing varies
gaps range from 9 days to 11 months
Nearly every release is documented
notes for 60 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
8 years old
130 releases · first in 2018
Added convenience function utils.openMsgBulk (imported to extract_msg namespace) for opening message paths with wildcards. Allows you to open several
0.34.1
utils.openMsgBulk (imported to extract_msg namespace) for opening message paths with wildcards. Allows you to open several messages with one function, returning a list of the opened messages.utils.unwrapMsg which recurses through an MSGFile and it's attachments, creating a series of linear structures stored in a dictionary. Useful for analyzing, saving, etc. all messages and attachments down through the structure without having to recurse yourself.[TeamMsgExtractor #102] Added the option to directly save body to pdf. This requires that you either have wkhtmltopdf on your path or that you provide
v0.34.0
pdf = True to save to turn it on. More details in the doc for the save function. You can also do this from the command line using the --pdf option, incompatible with other body types.--glob option for allowing you to provide an msg path that will evaluate wildcards.argparse let me know.chardet as a requirement to help work around an error in RTFDE.ignoreRtfDeErrors has been added to the MessageBase class and openMsg. It can also be enabled from the command line with --ignore-rtfde. This option will make it so all exceptions will be silenced from the module.One column per quarter.
[TeamMsgExtractor #212] Added support for Task objects.
v0.33.0
overrideClass to all _ensureSetX type functions. This parameter is a class to initialize using the data, if provided. The data will be provided as the first argument to the __init__ function of the class if the data is not None. If the data is done, the value set and returned from _ensureSetX will be None. This can be overriden using the second added parameter, which defaults to this behavior. Simply set preserveNone to False to force the data to be passed to the class. Keep in mind that this means the class will receive None as it's first parameter.Named class to make it more like the dictionary it is build on top of. Specifically, added keys, values, and items as functions.Named where old code wasn't deleted, causing some named properties to be completely omitted.Named by making it so get no longer copied the entire dictionary repeatedly while looking for the property.Attachment that caused embedded msg files to still regenerate the Named instance even though they should have been using the parent's.MSGFile to use enums.MSGFile.[TeamMsgExtractor #217] Redesigned named properties to be much more efficient. All in all, load times for MSG files are significantly improved all aro
v0.32.0
Named has been updated so it's methods are more standardized.Named is no longer usable to directly access property values. Instead,
access to them is done through NamedProperties._registerNamedProperty has been removed due to no longer being part of the named properties framework.Attachment.type to an enum instead of a string. This makes it easier to see all of the possible values.Message.save.Updated signed attachment mimetype property from mime to mimetype to match with the regular attachment property.
v0.31.1
mime to mimetype to match with the regular attachment property.Converted many arguments for msg files to keyword arguments (kwargs). This is a breaking change if your code provides anything except the path to the…
v0.31.0
**kwargs). This is a breaking change if your code provides anything except the path to the msg file. This will, however, make it easier to add arguments without the function signature being polluted with numerous arguments.AttachmentBase class where possible to allow more usability with broken and unsupported attachments. Nothing about these properties required the attachment to be fully processed, which is why they were moved down. From the perspective of using the Attachment class nothing has changed. The following properties have been moved: attachmentEncoding, additionalInformation, cid/contentId, longFilename, renderingPosition, and shortFilename.MissingEncodingError is being removed from the module entirely, as it is no longer a thing.Fixed major bug in MSGFile.listDir that would cause it to give the wrong data due to caching. I forgot to have it cache a different result for each se
v0.30.14
MSGFile.listDir that would cause it to give the wrong data due to caching. I forgot to have it cache a different result for each set of options, so it would always give the same result regardless of options after the first access.setup.py.README.[TeamMsgExtractor #257] Fixed missing documentation for customPath keyword argument to Attachment.save.
v0.30.13
customPath keyword argument to Attachment.save.[TeamMsgExtractor #253] Fixed various docstring issues.
v0.30.12
[TeamMsgExtractor #249] Fixed an error with opening the body causing the file to throw an uncaught exception in the __init__ function of MessageBase.
v0.30.11
__init__ function of MessageBase. The error may still come up later, but you will still have general access to the instance.[TeamMsgExtractor #249] Fixed exception catching not properly accessing the exception (forgot to go through one of the submodules to access exception)
v0.30.10
MessageBase.deencapsulatedRtf.Fixed the behavior of Properties.get so it actually behaves like a dict (that was the intent of it, but I did it the wrong way for some reason).
v0.30.9
Properties.get so it actually behaves like a dict (that was the intent of it, but I did it the wrong way for some reason).Update imapclient requirement to >=2.1.0 instead of ==2.1.0. Currently there are no changes that would prevent current future versions from working.
v0.30.8
imapclient requirement to >=2.1.0 instead of ==2.1.0. Currently there are no changes that would prevent current future versions from working.[TeamMsgExtractor #239] Fixed msg.py not having import pathlib.
v0.30.7
import pathlib.<html>, <head>, nor <body> tag, and so would have had an error. This will actually prevent the header from injecting properly as well, so a bit of validation before was made necessary to ensure the HTML saving would still work.BadHtmlError.utils.validateHtml.Small adjustments to internal code to make it a bit better.
v0.30.6
Message.getSaveBody, Message.getSaveHtmlBody, and Message.getSaveRtfBody. These three functions generate their respective bodies that will be used when saving the file, allowing you to retrieve the final products without having to write them to the disk first. All arguments that are passed to Message.save that would influence the respective bodies are passed to their respective functions.attachmentsOnly to Message.save but apparently it was missing. Not sure what happened there but I made sure it was added this time.Message.save called charset. This is used in the preparation of the HTML body when using preparedHtml. This is also usable with --charset CHARSET from the command line.[TeamMsgExtractor #225] Added the ability to generate the HTML body from the RTF body if it is encapsulated HTML. If there is no RTF body, then it wil
v0.30.5
Message.save for the attachmentsOnly option.[TeamMsgExtractor #233] Added option to Message.save to only save the attachments (attachmentsOnly). This can also be used from the command line with
v0.30.4
Message.save to only save the attachments (attachmentsOnly). This can also be used from the command line with the option --attachments-only.Message.save.Message.save instead of being chained with elif. Probably an artifact left from adding support for HTML and RTF.[TeamMsgExtractor #232] Updated list of known MSG class types so the module would correctly give UnsupportedMSGTypeError instead of UnrecognizedMSGTyp
v0.30.3
UnsupportedMSGTypeError instead of UnrecognizedMSGTypeError.Fixed typo in utils.knownMsgClass.
v0.30.2
utils.knownMsgClass.[TeamMsgExtractor #102] Added property MessageBase.htmlBodyPrepared which provides the HTML body that has been prepared for actual use or conversion t
v0.30.1
MessageBase.htmlBodyPrepared which provides the HTML body that has been prepared for actual use or conversion to PDF. All attachments that can be injected into the body directly will be injected.Message.save.utils.setupLogging to use pathlib.utils.setupLogging.utils.getContFileDir.Exception being raised at the end of utils.injectRtfHeader if the injection failed. This now raises RuntimeError, an error that should be reported so the injection system can be improved.utils.parseType.FolderID, MessageID, and ServerID to data.utils.parseType.Removed all support for Python 2. This caused a lot of things to be moved around and changed from indirect references to direct references, so it's po
v0.30.0
.formats into f strings.utils.bytesToGuid to make it faster and more efficient.utils.msgEpoch to utils.filetimeToUtc to be more descriptive.__main__ works. This does not affect the output it will generate, only the efficiency and readability.Corrected error string for incompatible options in Message.save.
v0.29.6
Message.save.Updated list of known MSG class types so the module would correctly give UnsupportedMSGTypeError instead of UnrecognizedMSGTypeError.
v0.29.5
UnsupportedMSGTypeError instead of UnrecognizedMSGTypeError.Fixed typo in utils.knownMsgClass.
v0.29.4
utils.knownMsgClass.[TeamMsgExtractor #226] Fix typo in command parsing that prevented the usage of allowFallback.
v0.29.3
allowFallback.customPath.--html option was being using for both html and rtf. This meant if you wanted rtf it would not have used it, and if you wanted html it would have thrown an error.--out-name having no effect.--out having no effect.Fixed issue where the RTF injection was accidentally doing HTML escapes for non-encapsulated streams and *not* doing escapes for encapsulated streams.
v0.29.2
Message.save causing bad logic. For context, the internal variable zip was renamed to _zip to avoid a name conflict with the built-in function. Some instances of it were missed.[TeamMsgExtractor #198] Added a feature to save the header in it's own file (prefers the full raw header if it can find it, otherwise puts in a genera
v0.29.1
[TeamMsgExtractor #207] Made it so that unspecified dates are handled properly. For clarification, an unspecified date is a custom value in MSG files
v0.29.0
datetime.datetime.max is returned. While perhaps not the best solution, it will have to do for now.utils.parseType was returning a string for the date when it makes more sense to return an actual datetime instance.Message.defaultFolderName. This property returns the default name to be used for a Message if none of the options change the name.useFileName (now useMsgFilename) argument in the save function.IPM will now be returned as MSGFile by openMsg, as this specifies that no format has been specified.UnsupportedAttachment instead of BrokenAttachment.openMsg will now tell you if a class type is simply unsupported rather than unrecognized. If it is found in the list, the function will raise UnsupportedMSGTypeError.MSGFile.listDir. I found that if you have larger files this single function might be taking up over half of the processing time because of how many times it is used in the module.Contact class to have more properties.MSGFile._ensureSetTyped which acts like the other ensure set functions but doesn't require you to know the type. Prefer to use other ensure set function when you know exactly what type it will be.Message.saveRaw to MSGFile.saveRaw.MSGFile.saveRaw to take a path and save the contents to a zip file.None.raw keyword of Message.save now actually works.Attachment.randomFilename which allows you to get the randomly generated name for attachments that don't have a usable one otherwise.Attachment.regenerateRandomName for creating a new random name if necessary.Attachment.getFilename. This function is used to get the name an attachment will be saved with given the specified arguments. Arguments are identical to Attachment.save.Attachment.save and Message.save. Simply pass a path for the zip keyword argument and it will create a new ZipFile instance and save all of it's data inside there. Alternatively, you can pass an instance of a class that is either a ZipFile or ZipFile-like and it will simply use that. When this argument is defined, the customPath argument refers to the path inside the zip file.html and rtf keywords to Message.save. These will attempt to save the body in the html or rtf format, respectively. If the program cannot save in those formats, it will raise an exception unless the allowFallback keyword argument is True.utils.hasLen to use hasattr instead of the try-except method it was using.recipientSeparator to MessageBase allowing you to specify a custom recipient separator (default is ";" to match Microsoft Outlook).openMsg function in Attachment to not be strict. This allows you to actually open the MSG file even if we don't recognize the type of embedded MSG that is being used.compressed-rtf module so we can take advantage of that.MessageBase._genRecipient to improve it (because what on earth was that code it was using before?). Variables in the function are now more descriptive. Added comments in several places.dev.setup_dev_logger to dev.setupDevLogger.MSGFile.fix_path to MSGFile.fixPath.MessageBase.save_attachments to MessageBase.saveAttachments.*.Exists to exists.*.ExistsTypedProperty to *.existsTypedProperty.prop.create_prop to prop.createProp.Properties.attachment_count to Properties.attachmentCount.Properties.next_attachment_id to Properties.nextAttachmentId.Properties.next_recipient_id to Properties.nextRecipientId.Properties.recipient_count to Properties.recipientCount.utils.get_command_args to utils.getCommandArgs.utils.get_full_class_name to utils.getFullClassName.utils.get_input to utils.getInput.utils.has_len to utils.hasLen.utils.setup_logging to utils.setupLogging.constants.int_to_data_type to constants.intToDataType.constants.int_to_intelligence to constants.intToIntelligence.constants.int_to_recipient_type to constants.intToRecipientType.Nothing published for this version
Nothing published for this version
[TeamMsgExtractor #189] Forgot to import prepareFilename in attachment.py.
v0.28.5
prepareFilename in attachment.py.[TeamMsgExtractor #184] Added code to Message to ensure subjects with null characters get stripped of them.
v0.28.4
Message to ensure subjects with null characters get stripped of them.prepareFilename in utils.Fixed minor typo in an exception description.
v0.28.3
Started preparing more of the code for when HTML and RTF saving are fully implemented. Please note that they do not work at all right now. Commented o
v0.28.2
IncompatibleOptionsError. It was supposed to be added a few updates ago, but was accidentally left out.Message.save to return the current Message instance to allow for chained commands. This allows you to do something like extract_msg.openMsg("path/to/message.msg").save().close() where you could not before.[TeamMsgExtractor #181] Fixed issue in Attachment that arose when moving some of the code to a base class.
v0.28.1
Attachment that arose when moving some of the code to a base class.utils.parse_type that caused it to incorrectly compare expected and actual length. Fortunately, this had no actual effect aside from a warning.ebcdic module to the requirements to add more supported encodings.[TeamMsgExtractor #87] Added a new system to handle NotImplementedError and other exceptions. All msg classes now have an option called attachmentErro
v0.28.0
NotImplementedError and other exceptions. All msg classes now have an option called attachmentErrorBehavior that tells the class what to do if it has an error. The value should be one of three constants: ATTACHMENT_ERROR_THROW, ATTACHMENT_ERROR_NOT_IMPLEMENTED, or ATTACHMENT_ERROR_BROKEN. ATTACHMENT_ERROR_THROW tells the class to not catch and exceptions and just let the user handle them. ATTACHMENT_ERROR_NOT_IMPLEMENTED tells the class to catch NotImplementedError exceptions and put an instance of UnsupportedAttachment in place of a regular attachment. ATTACHMENT_ERROR_BROKEN tells the class to catch all exceptions and either replace the attachment with UnsupportedAttachment if it is a NotImplementedError or BrokenAttachment for all other exceptions. With both of those options, caught exceptions will be logged.Attachment has been moved to a new class called AttachmentBase. Both BrokenAttachment and UnsupportedAttachment are subclasses of AttachmentBase meaning data can be extracted from their streams in the same way as a functioning attachment.[TeamMsgExtractor #177] Fixed incorrect struct being used. It should be the correct one now, but further testing will be required to confirm this.
v0.27.16
extract_msg.prop to actually format a value into the message.[TeamMsgExtractor #177] Fixed missing import.
v0.27.15
[TeamMsgExtractor #173] Fixed typo that I made in the last version that broke things. I didn't have the resources to test this one myself, unfortunate
v0.27.14
Nothing published for this version
[TeamMsgExtractor #173] Made an assumption about where an exception was thrown from and was wrong. While that location would have throw an exception,
v0.27.12
[TeamMsgExtractor #173] Tentatively implemented type 0x1014 (PtypMultipleInteger64). Apparently I forgot to do it earlier.
v0.27.11
Nothing published for this version
[TeamMsgExtractor #161] Added commands to the command line that will allow the user to specify that they want the message data to be output to stdout
v0.27.9
constants.CODE_PAGES to give more information about what it is. As it is a list of the possible encodings an msg file can use, I also specified which ones were supported by Python 3.[TeamMsgExtractor #158] Fixed a spelling error in a function name that was causing it to not be seen. The function was called ceilDiv but was accident
v0.27.8
ceilDiv but was accidentally called as cielDiv.Nothing published for this version
v0.27.6 * Fixed a few lines in data.py.
v0.27.6
data.py.Fixed an error in utils.divide that would cause it to drop the extra data if there was not enough to create a full division. For example, if you had a
v0.27.5
utils.divide that would cause it to drop the extra data if there was not enough to create a full division. For example, if you had a string that was 10 characters, and divided by 3, you would only receive a total of 9 characters back.[mattgwwalker #152] Fixed an issue where the name of an exception was put as the wrong thing.
v0.27.4
[mattgwwalker #105] Added code to fix an internal msg issue that had recipient lists being split up in the header after a certain amount of characters
v0.27.3
MessageBase class directly from extract_msg. I forgot to do this when I created it.MessageBase.bcc. I think it used to exist but got erased somehow on accident. Either way, it exists now.Nothing published for this version
[mattgwwalker #147]Fixed an issue in Message.save caused by it attempting to directly access a private variable that was moved to the base class Messa
v0.27.1
Message.save caused by it attempting to directly access a private variable that was moved to the base class MessageBase.[mattgwwalker #143] Added new class Appointment that can handle outlook appointments or meetings.
v0.27.0
Appointment that can handle outlook appointments or meetings.MessageBase for classes that end up being mostly like the Message class. Currently subclassed by Message and Appointment. This should not have a direct effect on any code that uses this module.PtypFloatingTime in utils.parseType.PtypTime in FixedLengthProp.parseTypeProperties class and the Named class.MSGFile._ensureSetProperty that acts like MSGFile._ensureSet except that it works with properties from the Properties instance.Attachment class and the Recipient class.Added new function MSGFile._ensureSetNamed which acts like MSGFile._ensureSet except that it works with named properties.
v0.26.4
MSGFile._ensureSetNamed which acts like MSGFile._ensureSet except that it works with named properties.Attachment and Recipient classes.data.py that contains various data structures that are used for specific properties.Recipient class by adding more properties.Named.getNamed and Named.getNamedValue which retrieves a named property or the value of a named property, respectively, based on its name.Added new function MSGFile.save that causes it and subclasses to raise a NotImplementedError if they do not override it.
v0.26.3
MSGFile.save that causes it and subclasses to raise a NotImplementedError if they do not override it.Nothing published for this version
Fixed an issue in openMsg that would leave the basic MSGFile instance open with the function returned, even if the function was returning a specific m
v0.26.1
openMsg that would leave the basic MSGFile instance open with the function returned, even if the function was returning a specific msg instance.Nothing published for this version
Nothing published for this version
Added new property Message.isRead to show whether the email has been marked as read.
v0.24.4
Message.isRead to show whether the email has been marked as read.Message.header_dict to Message.headerDict to better match naming conventions.Message.message_id to Message.messageId to better match naming conventions.Your coding agent can read these notes before it upgrades. Set up the MCP server →