OfficeIMO.Email 3.6.1

Prefix Reserved
dotnet add package OfficeIMO.Email --version 3.6.1
                    
NuGet\Install-Package OfficeIMO.Email -Version 3.6.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="OfficeIMO.Email" Version="3.6.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="OfficeIMO.Email" Version="3.6.1" />
                    
Directory.Packages.props
<PackageReference Include="OfficeIMO.Email" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add OfficeIMO.Email --version 3.6.1
                    
#r "nuget: OfficeIMO.Email, 3.6.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package OfficeIMO.Email@3.6.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=OfficeIMO.Email&version=3.6.1
                    
Install as a Cake Addin
#tool nuget:?package=OfficeIMO.Email&version=3.6.1
                    
Install as a Cake Tool

OfficeIMO.Email

Read local messages without retaining source handles

EmailMessageReader provides a body and attachment metadata view over local email files and offline archives:

using OfficeIMO.Email;

EmailMessageReadResult result = EmailMessageReader.Read("Archive.pst",
    new EmailMessageQuery { SubjectContains = "invoice", First = 25 });
foreach (OfficeIMO.Email.EmailMessage message in result.Messages) {
    Console.WriteLine(message.TextBody);
    EmailAttachmentExtractionResult files = message.SaveAttachments("attachments/" + message.ExportName,
        message.Attachments.Where(a => a.FileName?.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase) == true)
            .Select(a => a.Index));
    message.Save("copies/" + message.ExportName + ".eml",
        options: new EmailWriterOptions(EmailConversionLossPolicy.Warn));
}

The reader closes before returning. Payload operations reopen the unchanged source for their duration and remain cancellable through serialization or extraction. Keep the source file available and unchanged; views are local locators, not persisted checkpoints. Raw HTML bodies remain untrusted; the optional HTML bridge supplies sanitized local copies. ContentAvailability reports offline store cache limitations.

Folder accepts an exact path or unique folder name, Recurse includes descendants, and date bounds use received date with sent-date fallback. First defaults to 1,000 matches in source order; StoppedAtScanLimit explicitly reports a bounded search. Use EmailMessageStore.Open(path) in a using scope to reuse one reader for several queries; returned views remain usable after that scope closes. Directory-backed stores remain available through the lower-level data APIs.

Attachment extraction and draft composition

Extract decoded attachments into a directory controlled by the application:

EmailAttachmentExtractionResult extraction = EmailAttachmentExtractor.Extract(message, "attachments",
    new EmailAttachmentExtractionOptions(recurseEmbeddedMessages: true));

foreach (EmailAttachmentExtractionEntry entry in extraction.Entries) {
    Console.WriteLine($"{entry.SourcePath}: {entry.OutputPath} {entry.Sha256}");
}

The result is a hash and provenance manifest. Each entry keeps its original filename, logical attachment indexes, committed path, byte count, and diagnostics. Portable filenames include a deterministic index and source-path hash. Existing files are never overwritten. Embedded messages are exported as EML through the regular writer, so their conversion and signature policies still apply. Linked attachment paths are never opened, hidden attachments are excluded by default, and inline attachments can be excluded explicitly. The defaults visit at most 1,000 entries, allow 64 MiB per file and 256 MiB per operation, and permit four levels of nested attachment traversal when enabled. A rejected streaming payload may consume one sentinel byte beyond its limit. The aggregate budget counts decoded source reads, including failed attempts, and generated embedded EML bytes. Embedded source content is staged once through the shared writer staging owner; it is not reopened during serialization. ExtractAsync stages and copies source streams asynchronously. Earlier committed files remain available if a later attachment fails or the operation is cancelled. Keep the destination directory under application control while extraction runs.

Create reply and forward artifacts without sending them:

var composition = new EmailCompositionOptions();
composition.OwnAddresses.Add("alias@example.com");
EmailCompositionResult reply = EmailComposer.ReplyAll(message,
    new EmailAddress("me@example.com", "Example User"), "Thanks for the update.", composition);
reply.Document.Save("reply.eml");

Reply prefers Reply-To over From. ReplyAll also selects the original To/Cc recipients, excludes the composing address and configured aliases, and deduplicates addresses. Bcc is never copied. Exchange directory addresses that need resolution produce diagnostics. The new draft receives References and In-Reply-To, bounded to the most recent 100 identifiers by default. Source transport headers, signatures, MAPI metadata, attachments, and the original Message-ID are not inherited.

Forward starts with no recipients or attachments; add the intended recipients and attachments explicitly. These builders quote the plain-text alternative, with a 256 KiB character limit and Unicode-safe truncation. HTML-only messages return a missing-plain-body diagnostic. Inspect the result before handing a draft to a transport such as Mailozaurr.

Create a field-selected share copy

Create an independent EML model with a reviewed plain-text body:

EmailShareCopyResult share = EmailShareCopy.Create(message, new EmailShareCopyOptions {
    ReplacementSubject = "Shared discussion",
    ReplacementBodyText = "Text reviewed for sharing"
});
share.Document.Save("share.eml");

The default copies the original plain-text body and omits the original envelope, Bcc, threading, extra headers, attachments, HTML/RTF, raw source, MAPI/TNEF metadata and protected wrappers. RetainedFields selects subject, author, To/Cc or date. AddressReplacements replaces selected addresses or omits them with a null replacement; display names require KeepDisplayNames. RetainedHeaderNames selects extra headers, while envelope (including Resent-*), MIME and integrity headers remain owned by the new artifact. Changes records copied, replaced and omitted field paths without original values. Diagnostics explain removed integrity evidence and unavailable plain bodies.

Select ordinary attachment indexes explicitly through AttachmentIndexes. Selected payload bytes are copied independently and remain unchanged; generic filenames are used unless explicitly retained or replaced through AttachmentNames. Linked paths are never opened, and embedded messages require separate field-selected copies. Defaults allow 100 selected attachments, 64 MiB per payload, 256 MiB total, and 2 Mi characters per retained text field. The source document is unchanged.

Review retained body text, selected extra headers and opaque attachment content before sharing. Field selection does not anonymize their contents or preserve the original signature assurance. The optional HTML bridge supplies bounded text projection and selected concealed-content cleanup.

OfficeIMO.Email provides a first-party engine for persisted email and Outlook artifacts without a third-party message, compound-file, MIME, RTF, or platform-UI runtime.

dotnet add package OfficeIMO.Email

S/MIME structure detection and unchanged protected-message pass-through are included without a cryptographic package. Install the provider only when the application signs, encrypts, verifies, or decrypts S/MIME:

dotnet add package OfficeIMO.Security

Email reads expose an aggregate ProcessingBudget snapshot. MIME, MSG, embedded TNEF, and streaming payload paths share one operation ledger, so nested parsers do not receive fresh attachment, property, or structural allowances. EmailLimitExceededException.Diagnostic carries a stable actionable non-sensitive diagnostic automatically; store limits expose the equivalent through EmailStoreDiagnostic.FromLimit.

Store table, content-search, and OAB search checkpoints are versioned persistence values bound to a complete-source SHA-256 and exact query signature. Persist the checkpoint's Value, parse it after restart, and expect resume to fail closed if the source bytes or query changed. Creating a durable checkpoint intentionally reads the complete selected source to establish that identity.

EmailStoreSession.SearchWithReport adds scan/result completion evidence to lightweight metadata search. SearchContent supplies semantic field matches, snippets and durable batch continuation. Each content match also exposes ResumeAfter, a checkpoint immediately after that item; consumers returning only a prefix of a batch can resume there without losing the remaining matches.

For repeated queries over one store file, use EmailStoreSession.OpenSnapshot(path) or its stream overload. The session makes a bounded private copy and hashes it while copying, then reuses the complete-source SHA-256 for queries and checkpoints. Caller-side changes after opening cannot change the snapshot's results. Keep the original source stable while it is copied and dispose the session to remove its temporary file. Opening a new snapshot still validates checkpoints against the newly copied bytes; ordinary sessions continue to check the source before and after durable queries. Directory sessions are live catalogs: durable queries verify file membership, logical folders, and source content before and after scanning. A changed catalog requires reopening; directory snapshots are not implemented.

EmailStoreSession.PlanMaintenance is read-only and source-bound. It returns CompleteInspection rather than None whenever item, recovery, structural page, block, or byte bounds leave evidence incomplete, or when requested structural verification is unsupported for the source format. Executable repair remains a separate operation through recovery export, PST compaction, or PST split planning; OfficeIMO never repairs the opened source in place and rewrite paths require semantic post-verification.

The package supports:

  • EML and MIME messages, including multipart bodies, encoded headers, inline resources, attachments, and embedded messages
  • Outlook MSG and OFT files with standard and named MAPI properties, legacy code pages, recipients, embedded messages, linked attachments, and OLE/custom-storage attachments
  • MS-OXRTFCP compressed and uncompressed RTF bodies, including bounded expansion and checksum validation
  • Outlook messages, appointments, contacts, tasks, journals, and sticky notes with typed read/write models
  • standalone iCalendar (.ics) and vCard (.vcf/.vcard) documents with ordered, lossless content-line mutation, validation, bounded I/O, and standards-based EML projection
  • TNEF payloads such as winmail.dat
  • mboxo and mboxrd mailbox archives
  • PST, OST, Outlook for Mac OLM, EMLX, Apple Mail, Maildir, and mailbox-directory stores
  • Outlook Offline Address Book discovery, v4 entry decoding, search, validation, and offline identity resolution
  • one mixed-artifact discovery API for individual messages, calendars, contacts, stores, and OAB files
  • reopenable attachment content, file-backed streaming reads, and per-message mbox streaming for large or store-backed workflows
  • bounded synchronous and genuinely asynchronous source/destination I/O, immutable reader configuration, cancellation, and structured diagnostics
  • deterministic EML, MSG, OFT, TNEF, and mbox writing with explicit conversion-loss policy
  • versioned semantic fingerprints and value-free comparison reports for migration verification and deduplication

MSG output includes the root storage identity, complete named-property forward and reverse mappings, and the compatibility metadata required by native Outlook. A document without an explicit date receives a deterministic creation-time fallback; set Date or MessageMetadata.CreatedDate when the real timestamp matters.

The package depends on OfficeIMO.Rtf, which owns RTF syntax and semantic conversion. OfficeIMO.Email directly declares Microsoft's code-page compatibility library because its MIME, MSG, and TNEF readers use legacy character encodings themselves. MSG compound storage is shared OfficeIMO source compiled into OfficeIMO.Email; it is not a public general-purpose CFB package. This keeps the product graph explicit without copying RTF or CFB logic into the facade.

Read and write a message

using OfficeIMO.Email;

EmailDocument message = EmailDocument.Load("message.msg");

Console.WriteLine(message.Subject);
Console.WriteLine(message.Body.Text);

message.Save("message.eml");

Save infers EML, MSG, OFT, or TNEF from .eml, .mime, .msg, .oft, .tnef, or winmail.dat. The convenience methods throw InvalidDataException instead of silently returning a partial document or output when an error diagnostic is produced. Use the explicit overload only when the destination name has another extension:

message.Save("artifact.bin", EmailFileFormat.OutlookMsg);

The async API has the same shape:

EmailDocument message = await EmailDocument.LoadAsync("message.msg", cancellationToken: cancellationToken);
await message.SaveAsync("message.eml", cancellationToken: cancellationToken);

Path-based saves replace an existing destination by default. Use FailIfExists when exporting into a shared or user-managed directory where claiming a new filename must be atomic and an existing artifact must remain unchanged:

await message.SaveWithConflictPolicyAsync(
    "message.eml",
    EmailFileConflictPolicy.FailIfExists,
    cancellationToken: cancellationToken);

Use EmailDocumentReader when the host needs custom limits, raw-source preservation, or structured diagnostics:

var options = new EmailReaderOptions(
    maxInputBytes: 64L * 1024L * 1024L,
    maxAttachmentBytes: 32L * 1024L * 1024L,
    includeAttachmentContent: true);

EmailReadResult result = await new EmailDocumentReader(options).ReadDocumentAsync("message.msg");

foreach (EmailDiagnostic diagnostic in result.Diagnostics) {
    Console.WriteLine($"{diagnostic.Severity}: {diagnostic.Code}: {diagnostic.Message}");
}

if (result.HasErrors) {
    // The advanced API leaves recovery policy to the host.
}

When attachment payloads should not be retained in managed arrays, use the streaming reader. Ordinary MIME, MSG/OFT, and TNEF attachments become reopenable temporary-file sources while headers, bodies, recipients, and typed Outlook fields keep the same model:

using EmailReadResult result = await new EmailDocumentReader(options)
    .ReadDocumentAsync("large-message.msg", EmailReadContentStorage.TemporaryFiles, cancellationToken);

foreach (EmailAttachment attachment in result.Document.Attachments) {
    using Stream content = await attachment.OpenContentStreamAsync(cancellationToken);
    await content.CopyToAsync(destination, 81920, cancellationToken);
}

Dispose the EmailReadResult after consuming its file-backed content. Its temporary files and attachment sources belong to that result and become unavailable after disposal. Save, SaveAsync, Write, and WriteAsync consume ContentSource attachments through the same bounded writer pipelines instead of first materializing the complete artifact. The async path uses asynchronous source and destination I/O rather than wrapping the synchronous writer in a task.

The same model can be written as EML, MSG, OFT, or TNEF. Conversion is a load followed by a save:

EmailDocument.Load("source.eml").Save("converted.msg");

Known semantic loss is blocked by default. This includes changing or cross-converting a signed/encrypted artifact, dropping Outlook recurrence or time-zone blobs into iCalendar, converting an Exchange contact whose address depends on an opaque entry identifier, and writing journal or sticky-note semantics as EML. Analyze the conversion before opening a destination when the host needs to present those choices:

var writer = new EmailDocumentWriter();
EmailConversionReport report = writer.AnalyzeConversion(message, EmailFileFormat.Eml);

foreach (EmailDiagnostic diagnostic in report.Diagnostics) {
    Console.WriteLine($"{diagnostic.Severity}: {diagnostic.Code}: {diagnostic.Message}");
}

if (report.CanWrite) {
    EmailWriteResult result = writer.Write(message, "converted.eml");
    result.ThrowIfLoss();
}

Use EmailConversionLossPolicy.Warn only when the application has made an explicit decision to accept a documented loss. Opaque MAPI/TNEF metadata that has no portable EML equivalent is reported as a warning while common message content remains writable. Every artifact writer returns the same EmailWriteResult: SourceSelection says whether preserved bytes or regenerated model content was emitted, AttachmentContentLifetime records whether bounded content sources were opened for that operation, DiagnosticCodes retains stable evidence, and LossDisposition distinguishes no known loss, explicitly accepted loss, and a blocked write. Transport adapters can carry that result without defining another message or artifact model.

Regenerating a message with DKIM, DomainKey, or ARC signatures is blocked by default because serialization can invalidate those signatures. Choose new EmailWriterOptions(OfficeSignatureMutationPolicy.RemoveInvalidatedSignatures) to remove the signature chain from the output, or PreserveSignatureMarkup to retain it with an invalidation warning. The enum is in the OfficeIMO namespace. Neither option verifies signatures or overrides the separate S/MIME loss policy. Unchanged raw-source output preserves the original bytes and headers. Regenerated output omits retained Content-Length, Content-MD5, Content-Digest, Repr-Digest, and Digest headers and reports their removal. These policies also cover embedded messages and do not mutate the input model's header collection.

Use EmailAttachmentTextReader.Read(attachment, maxBytes, cancellationToken) for text attachments. It honors the MIME charset, uses a Unicode BOM when present, and returns the text, effective charset, bytes consumed, and decoding diagnostics. Charsetless text uses UTF-8 with Windows-1252 recovery; unavailable charsets and malformed byte sequences produce warnings. The byte limit applies to decoded attachment bytes before text decoding.

Compare message semantics

Semantic comparison hashes a canonical, versioned projection rather than serialized bytes. The migration profile normalizes store identity and serialization details, the strict profile includes representation details, and the deduplication profile excludes synchronization and modification state:

EmailSemanticComparisonReport comparison = EmailSemanticComparer.Compare(source, destination);

if (!comparison.IsMatch) {
    foreach (EmailSemanticDifference difference in comparison.Differences) {
        Console.WriteLine($"{difference.Kind}: {difference.Path}");
    }
}

Difference reports contain canonical paths and lengths, not message values. Before persisting fingerprints for private mail, provide a random digestKey through EmailSemanticComparisonOptions; the resulting HMAC-SHA-256 fingerprints cannot be correlated without that caller-owned key.

Read an mbox archive

An mbox file is an aggregate, so it has a dedicated reader rather than pretending to be one message:

var mailboxReader = new EmailMailboxReader();
EmailMailboxReadResult result = mailboxReader.Read("archive.mbox");

foreach (EmailMailboxEntry entry in result.Mailbox.Messages) {
    Console.WriteLine($"{entry.EnvelopeSender}: {entry.Document.Subject}");
}

EmailMailboxWriter writes mboxo or mboxrd with deterministic envelope and escaping behavior.

For a large mailbox, enumerate or write one entry at a time:

var reader = new EmailMailboxReader();

foreach (EmailMailboxEntryReadResult item in reader.ReadEntries("archive.mbox")) {
    Console.WriteLine(item.Entry.Document.Subject);
}

using Stream destination = File.Create("export.mbox");
new EmailMailboxWriter().WriteEntries(entries, destination);

ReadEntries retains at most one decoded message and restores a seekable caller-owned stream when enumeration ends. WriteEntries writes completed entries directly, so a later enumeration or size failure can leave earlier entries in the destination; use the aggregate EmailMailbox.Save API when atomic file replacement is required.

Outlook item projections

MSG and TNEF properties remain available through MapiProperties even when no convenience property exists. Common Outlook item fields are also projected onto typed models:

EmailDocument item = EmailDocument.Load("meeting.msg");

if (item.OutlookItemKind == OutlookItemKind.Appointment && item.Appointment is not null) {
    Console.WriteLine(item.Appointment.Start);
    Console.WriteLine(item.Appointment.End);
    Console.WriteLine(item.Appointment.Location);
}

Equivalent projections are available through Contact, Task, Journal, and Note.

Personal distribution lists use OutlookItemKind.DistributionList and OutlookDistributionList. Member and One-Off EntryIDs remain synchronized, validation enforces Outlook's per-property byte limit, and malformed identities keep their raw bytes and diagnostics. Meeting request/response/cancellation and task request/accept/reject/update items also have typed lifecycle projections instead of requiring message-class string switches.

Decoded appointment and task recurrence uses one OutlookRecurrence model across MSG, TNEF, and PST. Expansion is always bounded and stays in local-clock space until the caller supplies either a system time zone or the decoded Outlook time-zone definition:

OutlookRecurrenceExpansionResult occurrences = OutlookRecurrenceExpander.Expand(
    item.Appointment!.Recurrence!,
    new OutlookRecurrenceExpansionOptions {
        WindowStart = new DateTime(2026, 7, 1),
        WindowEnd = new DateTime(2026, 8, 1),
        MaxOccurrences = 500
    });

OutlookRecurrenceIcsExportResult exported =
    OutlookRecurrenceIcsConverter.Export(item.Appointment.Recurrence!);

Modified and deleted occurrences remain explicit. ICS import/export returns a conversion report and does not silently drop a recurrence pattern, exception, or time-zone constraint it cannot represent.

An Outlook template uses the same model and compound-file engine as MSG while retaining its template identity:

EmailDocument template = EmailDocument.Load("meeting.oft");
template.Subject = "Reusable meeting request";
template.Save("updated.oft");

Standalone iCalendar and vCard documents

EmailPortableContentExport.ToCalendar(item) exports an Outlook appointment or task as a standalone ICS stream. ToVCard(item) exports an individual contact. Both return an editable document, a detached UTF-8 byte snapshot and diagnostics. Unchanged imported semantic content retains its unknown properties. Regeneration uses the same loss checks as EML conversion and blocks opaque recurrence, nonportable addresses or changed imported semantics by default. Select EmailConversionLossPolicy.Warn explicitly when reviewing a lossy projection. These exports do not preserve the mail envelope, ordinary attachments or transport signatures.

When a message contains several projected calendar or contact MIME parts, export retains every matching part. The imported source byte limit applies across those parts, with at most 1,000 semantic parts per item. MIME calendar methods are carried into roots that omit METHOD. Unencoded vCard property charset declarations are updated to UTF-8; quoted-printable and Base64 payload spellings keep their source charset. These normalizations have explicit diagnostics. Decoded parsing allows bounded UTF-8 expansion without counting it as imported bytes.

EmailPortableContentExportResult<IcsDocument> exported =
    EmailPortableContentExport.ToCalendar(item);
File.WriteAllBytes("meeting.ics", exported.ToBytes());

EmailPortableContentExportResult<VCardDocument> cards =
    EmailPortableContentCollection.ToVCards(selectedContacts,
        new EmailPortableContentExportOptions(maxOutputBytes: 8 * 1024 * 1024));
File.WriteAllBytes("contacts.vcf", cards.ToBytes());

EmailPortableContentCollection.ToCalendars keeps separate VCALENDAR roots rather than combining timezone, UID or METHOD scopes. Collection output has one aggregate byte limit and an item limit. The source byte limit applies to each item's imported semantic content. Generated output is bounded while the codec accumulates it; these options do not limit the size of a caller-created in-memory Outlook model.

EmailContactConsolidation.Review takes provenance-tagged EmailContactSource contacts. It groups candidates by exact SMTP addresses and, when supplied, a complete OfflineAddressBookIdentityIndex with an unambiguous authoritative address match. Display names never create a match. Shared addresses can belong to different people, so a candidate group is a review suggestion. EmailContactSource.FromAddressBook uses the OAB owner's contact mapping and rejects distribution lists.

Review groups retain conflicting field variants, ordered repeated values, parameters and source IDs. Consolidate(review, groupIndex, choices) creates an independent vCard. Every conflicting field needs an explicit zero-based choice index keyed by EmailContactReviewField.Key; -1 explicitly omits that field. Required vCard fields, output size and property limits are checked. Reviewing contacts can project opaque Outlook identity data with warnings; inspect review.Diagnostics before consolidation. The APIs do not update a store or directory.

IcsDocument and VCardDocument expose the same ordered content-line model used by MIME projections. Repeated, grouped, unknown, IANA, and X- properties and their parameters remain available for inspection and mutation instead of being discarded by a narrow typed projection:

IcsDocument calendar = IcsDocument.Load("meeting.ics");
ContentLineComponent meeting = calendar.GetComponents("VEVENT").Single();
meeting.SetProperty("SUMMARY", "Updated planning meeting");
meeting.SetTemporalValue("DTSTART",
    IcsTemporalValue.Zoned(new DateTime(2026, 7, 20, 9, 0, 0), "Europe/Warsaw"));

IReadOnlyList<ContentLineValidationIssue> calendarIssues = calendar.Validate();
calendar.Save("updated.ics");

VCardDocument contacts = VCardDocument.Load("contacts.vcf");
ContentLineComponent contact = contacts.Cards[0];
contact.SetVCardText("FN", "Ada Lovelace");
contact.AddProperty("EMAIL", "ada@example.test").SetParameter("TYPE", "work");

IReadOnlyList<ContentLineValidationIssue> contactIssues = contacts.Validate();
contacts.Save("updated.vcf");

iCalendar temporal helpers retain DATE, floating, UTC, and TZID-local forms without resolving identifiers through the host operating system. RRULE helpers parse and update known recurrence parts while retaining unknown parts. vCard 2.1, 3.0, and 4.0 syntax is supported, including groups, repeated properties, binary/data-URI values, RFC 6868 parameter escaping, legacy quoted parameters, and quoted-printable continuation. Validation reports conformance issues; it does not erase vendor data. Legacy .vcs vCalendar files use the same preservation model, while validation continues to report constructs that are not RFC 5545 iCalendar 2.0.

When an appointment or task is written as EML, it becomes a text/calendar iCalendar part. Contacts become vCard attachments. Reminders become VALARM; task fields without a direct iCalendar property use valid X-OFFICEIMO-* extensions so they survive an OfficeIMO EML/MSG/TNEF cycle while remaining ignorable to other calendar readers. Reading those parts restores the corresponding typed model. Source calendar/vCard bytes are retained while the projected model is unchanged; editing a projected item is blocked by default when regeneration could omit unmodeled source properties. Meetings whose only attendee data is display text are also blocked because a valid iCalendar ATTENDEE requires an address. Journal and sticky-note models remain lossless across MSG/TNEF, but have no standard EML representation and therefore require an explicit non-blocking loss policy for EML output.

Properties that do not have a convenience field remain available through the typed Mapi property bag. The shared MapiKnownProperties vocabulary covers the standard and Outlook named properties understood by OfficeIMO, while custom named properties use the same strongly typed key contract:

string? displayName = item.Mapi.GetValueOrDefault(MapiKnownProperties.PidTag.DisplayName);

var customName = new MapiPropertyKey<string>(
    "CustomName",
    MapiPropertySets.PublicStrings,
    "CustomName",
    MapiPropertyType.Unicode,
    MapiPropertyType.String8);

string? customValue = item.Mapi.GetValueOrDefault(customName);
item.Mapi.Set(customName, "Retained with the artifact");

RTF bodies

EmailBody.Rtf contains the byte-preserving RTF source decoded from PidTagRtfCompressed. The MSG and TNEF writers serialize an assigned RTF body with the MS-OXRTFCP compression format, and the reader accepts both the LZFu and MELA forms.

RTF syntax editing and semantic conversion belong to OfficeIMO.Rtf. Generate RTF through that package when the source contains characters that need RTF escapes. OfficeIMO.Reader will route an RTF-only email body through the registered OfficeIMO.Reader.Rtf handler; without that optional adapter, it preserves the RTF source and reports the fallback explicitly.

Protected messages

EmailDocument.Protection detects opaque and clear-signed S/MIME plus signed or encrypted OpenPGP/MIME wrappers. It retains the original artifact bytes automatically, including Outlook's complete outer multipart/signed attachment for IPM.Note.SMIME.MultipartSigned. EmailSmime creates and verifies clear/opaque S/MIME, creates and decrypts EnvelopedData, and supports sign-then-encrypt through an explicitly supplied security provider; OpenPGP remains outside this package. Writing an unchanged protected document in its source format emits those bytes verbatim; an edited or cross-format write is blocked by default because regenerating the wrapper would invalidate its cryptographic meaning.

using System.Security.Cryptography.X509Certificates;
using OfficeIMO.Security;
using X509Certificate2 recipient = LoadRecipientCertificate();
using X509Certificate2 signingCertificate = LoadSigningCertificate();
EmailDocument protectedMessage = EmailDocument.Load("message.eml");
IOfficeSecurityProvider security = OfficeSecurityProvider.Default;

EmailSmimeVerificationResult verified = EmailSmime.Verify(protectedMessage, security);
if (verified.IsCryptographicallyValid) {
    Console.WriteLine(verified.SignedContent?.Subject);
}

EmailSmimeDecryptionResult decrypted = EmailSmime.Decrypt(protectedMessage, recipient, security);
if (decrypted.Decrypted) {
    Console.WriteLine(decrypted.DecryptedContent?.Body.Text);
}

EmailSmimeProcessingResult processed = EmailSmime.DecryptThenVerify(
    protectedMessage, recipient, security);
Console.WriteLine(string.Join(", ", processed.ProcessingOrder));

EmailDocument outgoing = new EmailDocument {
    Subject = "Protected report"
};
outgoing.Body.Text = "Attached report details";

EmailSmimeCreationResult signed = EmailSmime.Sign(
    outgoing,
    signingCertificate,
    security,
    EmailSmimeSignatureMode.ClearSigned);
File.WriteAllBytes("signed.eml", signed.Message);

EmailSmimeCreationResult encrypted = EmailSmime.SignAndEncrypt(
    outgoing,
    signingCertificate,
    new[] { recipient },
    security);
File.WriteAllBytes("signed-and-encrypted.eml", encrypted.Message);

Certificate/key discovery is intentionally not implicit. Verification accepts caller trust/revocation policy through CmsVerificationOptions and applies the S/MIME email-signing certificate purpose, including the standard email-protection EKU; creation and decryption require explicitly supplied certificates and a provider. The original protected document is never mutated, and the decrypted/signed projection is returned separately. Detached verification first uses the exact retained MIME bytes and, only when necessary, retries the standard CRLF canonical form used by S/MIME mail clients; SignedMimeEntity still exposes the original bytes and a structured diagnostic records the fallback. Results name the concrete provider and project signer identity, chain-building, revocation, timestamp, and offline-policy status into stable email diagnostic codes. DecryptThenVerify records and enforces the outer-decrypt, inner-verify order, while an unparseable protected entity remains available as retained bytes plus diagnostics. On .NET 8 and later, the Security provider decrypts RSA PKCS#1/OAEP with AES-CBC through the supplied platform key handle without exporting private parameters. Keychain identity selection remains caller-owned. Other envelope profiles and older targets require an exportable RSA key and report EnvelopePrivateKeyNotExportable when export is unavailable.

Mailbox stores and store-backed content

PST, OST, Outlook for Mac OLM, and Apple Mail EMLX containers are included in OfficeIMO.Email. The Store APIs yield ordinary EmailDocument instances while preserving folder paths, store metadata, diagnostics, and bounded attachment behavior.

EmailStoreSession.IsPstPasswordProtected and EmailStoreInspectionReport.IsPstPasswordProtected expose the PST header's password-protection state. PST uses a checksum-based access deterrent, not cryptographic content encryption; these properties do not claim confidentiality or decrypt content.

using OfficeIMO.Email.Store;

using EmailStoreSession session = EmailStoreSession.Open("archive.pst");
EmailStoreItemReference firstReference = session.EnumerateItems(
    new EmailStoreEnumerationOptions(maxItems: 1)).Single();
EmailDocument firstMessage = session.ReadItem(firstReference).Document;

session.AnalyzeArchive() returns read-only folder and UTC month distributions, large attachment metadata and semantic duplicate candidates. It projects bounded bodies, recipients and attachment metadata; it does not request attachment payloads or embedded-item content. Matching candidates can contain different attachment bytes and unloaded properties, so the report does not establish duplicate equality or select mail for deletion.

EmailArchiveAnalysisReport analysis = session.AnalyzeArchive(
    new EmailArchiveAnalysisOptions(maxItems: 10_000, maxLargeAttachments: 25));
Console.WriteLine($"Scanned {analysis.ItemsScanned}; exhausted references: {analysis.ExhaustedSelectedReferences}");
Console.WriteLine($"Candidate groups: {analysis.DuplicateCandidateGroupCount}");

The report rechecks a SHA-256 of the complete persisted source. That source hashing performs I/O even though attachment payloads are not decoded for analysis. OpenSnapshot can reuse its owned snapshot fingerprint. Header-only and potentially partial local items are excluded from candidate matching. Scan limits, failed analyses, source warnings, omitted distribution buckets, omitted candidate IDs/groups and diagnostic totals remain explicit. ExhaustedSelectedReferences describes the session's regular-reference enumeration; it does not prove that a damaged source catalog includes every original item. Failed analysis can occur after an item was projected. EstimatedCandidateDeclaredBytes uses available item size declarations and excludes the largest member in each candidate group. It is neither verified duplicate savings nor a physical PST compaction estimate. No archive is changed.

Long-running PST/OST/OLM/EMLX/Mbox/mail-directory migrations can opt into an atomic checkpoint. The checkpoint binds the exact source byte fingerprint, bounded source catalog, destination, conversion options, writer state, item provenance, and verification journal. Resume rejects changed sources or options instead of silently continuing against different data:

var options = new EmailStorePstConversionOptions(
    checkpointPath: "migration.checkpoint",
    checkpointIntervalItems: 500,
    partialResultPolicy: EmailStorePartialResultPolicy.RetainResumableState,
    verifyAfterWrite: true,
    failOnDataLoss: true);

EmailStorePstConversionReport migration = EmailStoreConverter.ConvertToPst(
    "source-mail", "destination.pst", conversionOptions: options);
Console.WriteLine($"{migration.Disposition}; resumed={migration.WasResumed}");

Attachment streams remain bounded and operation-scoped. A requested verification manifest records keyed fingerprints, ordinals, outcomes, and difference-path tokens without subjects, addresses, message content, filenames, or store IDs. Use DiscardIncompleteState when an interrupted migration must not retain its writer-owned staging files.

Use EmailDataArtifact.Open from the included OfficeIMO.Email.Data namespace when an application wants one discovery entry point across individual artifacts, stores, and OAB files. No additional package is required.

Outlook Express DBX

Open one Outlook Express message folder or open Folders.dbx by path to import the local folder hierarchy. Keep the referenced mailbox files beside the catalog. Folder names and parent links come from the catalog. An unavailable referenced mailbox is reported separately from an empty folder.

using OfficeIMO.Email.Store;

using EmailStoreSession source = EmailStoreSession.Open("Mail backup/Folders.dbx");
EmailStoreExportReport export = source.ExportToDirectory("Exported EML");
foreach (EmailStoreExportEntry entry in export.Entries) {
    Console.WriteLine(entry.DestinationPath);
}

Open a standalone message database such as Inbox.dbx from a path or a readable seekable stream. Use EmailStoreSession.OpenSnapshot for repeated metadata searches or EML export from a standalone DBX file. It copies the source into private temporary storage once and reuses that stable copy. Keep the original source stable until snapshot capture returns. Folders.dbx uses the live path-based catalog and sibling validation.

DBX import reads indexed local RFC messages and their MIME attachments. It supports Windows-1252 catalog names and reports malformed indexes and fragment chains. EML export serializes the projected message. DBX writing, deleted-item carving, remote account recovery, and earlier Outlook Express mailbox formats are outside this profile.

Native DBX original subject, importance and representable declared message size fill the existing typed metadata. MIME importance takes precedence over the native priority. Declared size is a source hint and never controls message admission, which uses the actual fragment lengths. Native strings retain the Windows-1252 qualification. Native subject text shares the selected read's decoded-property budget with MIME content.

Native DBX received times fill missing MIME arrival metadata. An existing MIME Received timestamp takes precedence. Directory export appends ReceivedAtUtc to the preservation manifest, retaining arrival metadata beside EML files. EMLX metadata stores whole-second arrival times. With the manifest disabled, export reports an omitted arrival time or loss of sub-second EMLX precision.

Apple Mail and Outlook for Mac

Open an exported Apple Mail .mbox package, its containing folder, or a copied Mail directory with EmailStoreSession.Open(path). Packages containing an aggregate mbox file and directories containing individual EMLX messages use the same folder and item APIs. Account directories remain part of folder identity, empty mailbox folders are retained, and AppleDouble ._ sidecars are skipped. MaxDirectoryEntryCount bounds every visited entry, including unrelated files and directories; message/attachment-storage file, item, folder, depth, and source-byte limits are separate.

EMLX reads support XML and binary property lists. document.Properties["Emlx:Metadata"] contains an ordinal, case-sensitive metadata dictionary. This is the authoritative editable catalog; flat Emlx:Metadata:* properties are read aliases and are used for writing only when no catalog exists. Editing and writing EMLX preserves unknown supported values and unknown flag bits while updating projected message flags. Unsupported or malformed trailers remain in Emlx:RawMetadata: Block rejects opaque metadata rewrites, while Warn and Allow copy the trailer unchanged and report that edits could not be reconciled. The default Block policy rejects exports that omit retained EMLX, OLM or MAPI/TNEF metadata, including regenerated embedded messages. Regenerated embedded messages also undergo the same calendar, contact and protected-content loss checks as the outer message, including task payloads synthesized from TaskCommunication.EmbeddedTask. Exact preserved MIME attachment payloads are copied without regenerating their projected models. Select new EmailWriterOptions(EmailConversionLossPolicy.Warn) to export the common message content with diagnostics for the omitted fields.

Live EMLX, mbox and OLM sessions validate their source with a bounded SHA-256 before and after each selected read, rejecting detected changes including same-length edits. Directory sessions pin each message and recovered attachment file when it is first projected, and reject subsequent content changes. A detected change expires retained attachment streams; reopen the session to read the changed source. The buffer size stays fixed, but each check reads the complete artifact or selected directory file. Use EmailStoreSession.OpenSnapshot for repeated reads of a standalone archive when a private stable copy can avoid repeated source hashing. The initial snapshot copy and hash perform source I/O. Use an exported or otherwise quiescent archive when the source is actively written; these reads do not take an atomic filesystem snapshot. Directory sessions recover empty MIME parts in Messages/<numeric-id>.partial.emlx from Attachments/<numeric-id>/<one-based-MIME-part-path>/<file>. For example, nested part 2.1 is the first child of the second root part. Each part directory must contain exactly one nonempty regular file. Recovery uses MIME identity rather than the attachment filename and never leaves the selected root or follows links. Opening just Messages or a standalone EMLX file cannot grant access to sibling storage.

Emlx:RecoveredPartCount and Emlx:UnresolvedPartCount describe the identified placeholders. Base64, quoted-printable, 7bit, 8bit and binary placeholders are reconstructed as Base64; original transfer formatting and payload-dependent integrity headers are not retained. Missing, ambiguous, malformed, unsupported-encoding and protected parts remain unavailable. Unresolved content is marked indeterminate in ContentAvailability and reported during conversion. Apple’s X-Apple-Content-Length is retained as provenance; it is not a verified decoded sibling length. Metadata reads also use a bounded temporary reconstruction to derive actual payload lengths. Selected streaming reads return session-owned content sources. Offline recovery cannot establish whether further content exists remotely, so partial sources retain a completeness diagnostic; Block rejects the conversion, while Warn and Allow accept it with that diagnostic. The qualification runner distinguishes the pinned independent storage fixture from native Apple Mail acceptance.

OLM sessions retain summaries and one bounded XML entry, then project selected records. They preserve nested, repeated, attributed, and case-colliding fields as XML fragments in Olm:StructuredProperties, and item attributes in Olm:ItemAttributes. Export reports archive metadata that has no target representation. OLM creation and rewriting are outside the contract.

using EmailStoreSession session = EmailStoreSession.Open("Mail Export");
EmailStoreItemReference reference = session.EnumerateItems().First();
EmailStoreItem selected = session.ReadItem(reference,
    new EmailStoreItemReadOptions(preferStreamingAttachmentContent: true));

EMLX, Mbox, mailbox-directory, and OLM selected reads honor the streaming preference. Decoded attachment files belong to the session; disposing it closes outstanding readers and expires their content sources. Repeated streaming reads consume the session's aggregate attachment and retained-read budgets. Keep the session open while writing or copying that content. ReadAll remains a materializing convenience and follows RetainAttachmentContent.

Store-backed attachment content

EmailAttachment.Content remains the simple in-memory representation. A mailbox or archive provider can instead set ContentSource to an IEmailContentSource that opens a fresh decoded stream on demand:

EmailAttachment attachment = item.Attachments[0];

using Stream content = await attachment.OpenContentStreamAsync(cancellationToken);
await content.CopyToAsync(destination, 81920, cancellationToken);

EML, MSG, and TNEF writers consume either representation through the same bounded path. The interface deliberately contains no PST, OST, MAPI, or Outlook types, so mailbox and store owners can yield ordinary EmailDocument instances while keeping source lifetime and property-stream access in the owning Store API area.

Safe HTML and text projection

Install the optional OfficeIMO.Email.Html bridge when a consumer needs one shared body-selection, RTF-fallback, sanitization, and resource-resolution contract. It chooses HTML, RTF, or plain text under an explicit policy, blocks remote resources by default, resolves CID/content-location/filename references, and exposes bounded operation-scoped resources plus a prepared HtmlConversionDocument. OfficeIMO.Email.Image and OfficeIMO.Reader.Email consume this same bridge; Reader can then project the prepared safe document to text or Markdown. The core OfficeIMO.Email package does not reference AngleSharp or another HTML engine.

Inspect local email data

OfficeIMO.Email.Data.EmailDataInspector reports metadata through the existing artifact readers:

using OfficeIMO.Email.Data;

EmailDataInspectionReport report = EmailDataInspector.Inspect("message.eml",
    new EmailDataInspectionOptions(maxSamples: 32));
foreach (EmailDataBodyAlternative body in report.Bodies)
    Console.WriteLine($"{body.Kind}: {body.CharacterCount} UTF-16 units; charset {body.DeclaredCharset}");

Individual-message reports include body alternatives, declared charsets, attachment metadata, protected-wrapper classification, transport-signature header names and bounded diagnostic code/severity samples. They omit body text, signature values, linked paths and original diagnostic messages, and never open deferred attachment streams. Signature presence does not establish authenticity: CryptographicallyVerified is false.

Store and OAB inspection reports catalogs and declared counts without projecting all messages or address-book entries. ICS/VCF inspection reports parsed root counts; use those format owners' Validate() operations for semantic validation. These reports do not promise completeness beyond the selected owner's catalog or read policy.

The default inspection profile bounds individual messages and decoded properties to 16 MiB, store files to 4 GiB and 10,000 items, and OAB components to 64 MiB. OpenOptions supplies explicit owner-specific policies; the overload accepting an existing EmailDataOpenResult keeps the caller's read policy and resource ownership. Sample truncation and a bounded signature-header scan are visible in the report. Install OfficeIMO.Email.Html for the optional HTML safety adapter. Inspection does not access the network, discover certificates, decrypt, verify signatures, follow linked attachments or change the source.

Resource limits

EmailReaderOptions is immutable and applies limits before retaining decoded content. It controls source size, header size and count, MIME part count and depth, per-attachment and aggregate attachment bytes, embedded-message depth, CFB directory entries, MAPI properties and decoded property bytes, and TNEF attributes.

Use includeAttachmentContent: false when only attachment metadata is needed. Parsing still validates the source structure, but ordinary decoded attachment payloads are not retained in the result model. Calendar and vCard parts that define the typed item are retained because they are semantic message content, not optional file payloads.

Reader integration

OfficeIMO.Reader.Email recognizes .eml, .msg, .oft, .mbox, .mbx, .tnef, winmail.dat, .ics, .vcs, .vcf, .vcard, PST, OST, OLM, EMLX, mailbox directories, and OAB data. Calendar and contact files route through the public IcsDocument and VCardDocument engines. Store and address-book projections live in that same adapter package; they add no separate NuGet layer and reuse this package's parsers and models. Rich results include envelope and Outlook metadata, structured diagnostics, materializable attachment assets, embedded messages, and chunks extracted through the Reader handlers configured by the host.

using OfficeIMO.Reader;
using OfficeIMO.Reader.Email;

OfficeDocumentReader reader = new OfficeDocumentReaderBuilder()
    .AddEmailHandlers()
    .Build();
OfficeDocumentReadResult result = reader.ReadDocument("message.msg");

Console.WriteLine(result.Source.Title);
foreach (OfficeDocumentAsset attachment in result.Assets) {
    Console.WriteLine($"{attachment.FileName}: {attachment.LengthBytes}");
}

Scope boundary

OfficeIMO.Email owns offline artifact parsing, serialization, and format-neutral Outlook data. It does not connect to mail servers, authenticate users, send messages, discover certificates or private keys, or implement DKIM, ARC, or OpenPGP. EmailSmime.Sign, Encrypt, SignAndEncrypt, Verify, Decrypt, and DecryptThenVerify are thin data-oriented adapters over a caller-supplied IOfficeSecurityProvider: Email owns bounded MIME construction and exact protected-byte handling, while the provider owns CMS, certificates, and trust policy. The adapters create signed or encrypted MIME, verify exact clear-signed bytes and opaque signed-data, decrypt caller-selected EnvelopedData recipients, retain the original protected artifact, and return a separate parsed protected-content document when possible. Certificate/key and provider selection remain explicit and caller-owned.

The package does not expose general-purpose CFB transactions. Its Store API area owns PST, OST, OLM, EMLX, Mbox, Apple Mail, and Maildir traversal, selection, validation, native export, verified conversion, multi-store merge, and verified atomic rewrite mutation of an existing Unicode PST. ANSI PST mutation, OST mutation/writing, in-place NDB editing, append, in-place repair, and password/encryption authoring remain outside the contract. Store also owns distinct-destination verified compaction and query/size-based split; neither operation edits the open source.

For exact pass-through of an ordinary unprotected artifact, read with preserveRawSource: true and write with usePreservedRawSource: true. Protected artifacts use safe unchanged pass-through automatically.

Dependency footprint

  • External: no third-party email engine or Outlook interop. System.Text.Encoding.CodePages supplies legacy encodings.
  • OfficeIMO: OfficeIMO.Core and OfficeIMO.Rtf. MIME, MSG/MAPI, TNEF, mbox, iCalendar, vCard, Store, OAB, protected-wrapper detection, and compressed-RTF handling remain first-party and ship in this package.
  • Optional security: install OfficeIMO.Security for S/MIME CMS/X.509 signing, encryption, verification, and decryption, or provide another IOfficeSecurityProvider. It is not a transitive Email dependency.
  • Optional HTML: install OfficeIMO.Email.Html for safe body/resource projection. HTML and RTF-to-HTML dependencies remain outside this core package.

See the complete OfficeIMO package map for related formats and conversion paths.

Generated capability summary

This table is generated from the package-neutral OfficeIMO operation catalog. The detailed source contracts remain authoritative for feature-level behavior and limitations.

Operation Supported Partial Preserved Rejected Unsupported Not applicable
Create 8 0 0 0 7 0
Read 15 0 0 0 0 0
Edit 6 0 4 1 4 0
Preserve 2 4 0 0 4 0
Inspect 15 0 0 0 0 0
Validate 11 0 0 0 0 3
Remove 0 0 0 0 1 4
Convert 12 0 0 0 0 0
Export 6 0 0 0 0 0

The complete rows for OfficeIMO.Email are published in the generated operation contract.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 is compatible.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (7)

Showing the top 5 NuGet packages that depend on OfficeIMO.Email:

Package Downloads
OfficeIMO.Reader

Unified, read-only document extraction facade for OfficeIMO (Word/Excel/PowerPoint/Markdown/PDF) intended for AI ingestion.

OfficeIMO.Email.Html

Dependency-isolated safe HTML, RTF, text, and inline-resource projection for OfficeIMO email artifacts.

OfficeIMO.Reader.Email

Unified email, MHTML, Outlook store, and Offline Address Book adapter for OfficeIMO.Reader.Core.

OfficeIMO.Mhtml

MHTML archive loading, saving, HTML projection, and embedded MIME resources for OfficeIMO.

Mailozaurr.Artifacts

OfficeIMO.Email and MimeKit interoperability for EML, MSG, OFT, TNEF, and protected-message artifacts.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.6.1 515 11/10/2026
3.6.0 768 11/6/2026
3.5.3 4,841 10/31/2026
3.5.2 3,906 10/24/2026
3.5.1 3,651 10/16/2026
3.4.5 1,096 10/10/2026
3.4.4 1,700 9/27/2026
3.4.3 2,602 9/12/2026
3.4.2 701 9/9/2026
3.4.1 414 9/7/2026
3.4.0 371 9/6/2026
3.3.0 353 9/2/2026
3.2.7 420 8/29/2026
3.2.6 989 8/22/2026
3.2.5 466 8/21/2026
3.2.4 4,322 8/19/2026
3.2.3 1,723 8/17/2026
3.2.2 1,646 8/13/2026
3.2.1 431 8/11/2026
3.2.0 623 8/7/2026
Loading failed