### Run the example app with npm or yarn Source: https://github.com/epfromer/pst-extractor/blob/master/readme.md Run the example app to walk the PST and print the folder structure to the console. The example uses a sample Enron dataset that can be replaced with your own PST file. ```bash cd example npm start ``` ```bash cd example yarn start ``` -------------------------------- ### Usage Example Source: https://github.com/epfromer/pst-extractor/blob/master/_autodocs/api-reference/PSTMessageStore.md Example of using PSTMessageStore to access the display name and node type, and a robust pattern for downstream processing. ```APIDOC ## Example ### Description Shows how to obtain the message store via PSTFile.getMessageStore() and access its properties. ### Code ```ts import { PSTFile } from 'pst-extractor' const pstFile = new PSTFile('archive.pst') // The store is available right after opening — no folder walk needed. const store = pstFile.getMessageStore() console.log(store.displayName) // e.g. "Personal folders" console.log(store.getNodeType()) // node type bits of the store descriptor // Robust pattern for downstream processing: try { const root = pstFile.getRootFolder() console.log(root.hasSubfolders ? 'root has subfolders' : 'root is empty') } catch (err) { // Parsing errors propagate as plain Error instances — see errors.md console.error((err as Error).message) } finally { pstFile.close() } ``` ``` -------------------------------- ### PSTActivity usage example Source: https://github.com/epfromer/pst-extractor/blob/master/_autodocs/api-reference/PSTActivity.md Example of iterating through a PST folder and processing journal entries. Imports PSTFile, PSTFolder, PSTActivity from 'pst-extractor', opens 'journal.pst', gets root folder, iterates children, checks for PSTActivity instances, logs journal details, and closes the file. ```typescript import { PSTFile, PSTFolder, PSTActivity } from 'pst-extractor' const pstFile = new PSTFile('journal.pst') const folder = pstFile.getRootFolder() let item: any = folder.getNextChild() while (item) { if (item instanceof PSTActivity) { console.log( `${item.subject} | type=${item.logType} (${item.logTypeDesc}) | ` + `${item.logStart} → ${item.logEnd} | ${item.logDuration} min` ) } item = folder.getNextChild() } pstFile.close() ``` -------------------------------- ### fileInputStream usage example Source: https://github.com/epfromer/pst-extractor/blob/master/_autodocs/api-reference/PSTAttachment.md Example of reading the attachment stream in chunks using the fileInputStream getter. ```typescript const stream = attachment.fileInputStream if (stream) { const bufferSize = 8176 const buffer = Buffer.alloc(bufferSize) let bytesRead do { bytesRead = stream.read(buffer) fs.writeSync(fd, buffer, 0, bytesRead) } while (bytesRead === bufferSize) } ``` -------------------------------- ### Install pst-extractor with npm or yarn Source: https://github.com/epfromer/pst-extractor/blob/master/readme.md Install the pst-extractor package using either npm or yarn. Both commands are equivalent alternatives for adding the dependency. ```bash npm install --save pst-extractor ``` ```bash yarn add pst-extractor ``` -------------------------------- ### PSTContact Source: https://github.com/epfromer/pst-extractor/blob/master/_autodocs/api-reference/PSTContact.md Documentation for the PSTContact class, including its properties and usage example. ```APIDOC ## PSTContact ### Description Represents a contact item in a PST file. It extends PSTMessage and provides access to contact-specific properties such as name, company, email addresses, and phone numbers. ### Usage Example ```ts import { PSTFile, PSTFolder, PSTContact } from 'pst-extractor' const pstFile = new PSTFile('contacts.pst') const root = pstFile.getRootFolder() let item: any = root.getNextChild() while (item) { if (item instanceof PSTContact) { console.log( `${item.givenName} ${item.surname} | ${item.companyName} | ` + `email=${item.email1EmailAddress} | ${item.businessTelephoneNumber}` ) } item = root.getNextChild() } pstFile.close() ``` ### Properties - **givenName** (string) - The contact's given name. - **surname** (string) - The contact's surname. - **companyName** (string) - The contact's company name. - **email1EmailAddress** (string) - The contact's primary email address. - **businessTelephoneNumber** (string) - The contact's business telephone number. ### Related - [PSTMessage](PSTMessage.md) — base class - [PSTUtil](PSTUtil.md) — `createAppropriatePSTMessageObject` maps `IPM.Contact` here - [types.md](../types.md) — `PidLid*` property IDs in `OutlookProperties` ``` -------------------------------- ### PST CRC table and ComputeCRC function Source: https://github.com/epfromer/pst-extractor/blob/master/doc/PST file format.pdf CRC table initialization and the ComputeCRC function for PST file CRC calculation. The table is a 256-entry DWORD array (shown partially) used by ComputeCRC, which processes the buffer in aligned 8-byte chunks and handles unaligned bytes at the start and end. The function uses multiple offset tables (CrcTableOffset32, 40, 48, 56, 64, 72, 80, 88) to compute the CRC efficiently. ```c 0xA9435C82, 0x65E95C1C, 0xEB665BFF, 0x27CC5B61, 0x2D095278, 0xE1A352E6, 0x6F2C5505, 0xA386559B, 0x061D761C, 0xCAB77682, 0x44387161, 0x889271FF, 0x825778E6, 0x4EFD7878, 0xC0727F9B, 0x0CD87F05, 0xD5F86DA9, 0x19526D37, 0x97DD6AD4, 0x5B776A4A, 0x51B26353, 0x9D1863CD, 0x1397642E, 0xDF3D64B0, 0x83D02561, 0x4F7A25FF, 0xC1F5221C, 0x0D5F2282, 0x079A2B9B, 0xCB302B05, 0x45BF2CE6, 0x89152C78, 0x50353ED4, 0x9C9F3E4A, 0x121039A9, 0xDEBA3937, 0xD47F302E, 0x18D530B0, 0x965A3753, 0x5AF037CD, 0xFF6B144A, 0x33C114D4, 0xBD4E1337, 0x71E413A9, 0x7B211AB0, 0xB78B1A2E, 0x39041DCD, 0xF5AE1D53, 0x2C8E0FFF, 0xE0240F61, 0x6EAB0882, 0xA201081C, 0xA8C40105, 0x646E019B, 0xEAE10678, 0x264B06E6 }; ``` ```c DWORD ComputeCRC(DWORD dwCRC, LPCVOID pv, UINT cbLength) { UINT i; DWORD dw2nd32; const byte *pbBuffer = (const byte *) pv; const UINT cbAlignedOffset = ((cbLength < sizeof(DWORD)) ? 0 : (UINT)((DWORD_PTR)pv % sizeof(DWORD))); const UINT cbInitialUnalignedBytes = ((cbAlignedOffset == 0) ? 0 : (sizeof(DWORD) -cbAlignedOffset)); const UINT cbRunningLength = ((cbLength < sizeof(DWORD)) ? 0 : ((cbLength -cbInitialUnalignedBytes) / 8) * 8); const UINT cbEndUnalignedBytes = cbLength -cbInitialUnalignedBytes -cbRunningLength; for(i=0; i < cbInitialUnalignedBytes; ++i) dwCRC = CrcTableOffset32[(dwCRC ^ *pbBuffer++) & 0x000000FF] ^ (dwCRC >> 8); for(i=0; i < cbRunningLength/8; ++i) { dwCRC ^= *(DWORD *)pbBuffer; dwCRC = CrcTableOffset88[ dwCRC & 0x000000FF] ^ CrcTableOffset80[(dwCRC >> 8) & 0x000000FF] ^ CrcTableOffset72[(dwCRC >> 16) & 0x000000FF] ^ CrcTableOffset64[(dwCRC >> 24) & 0x000000FF]; pbBuffer += 4; dw2nd32 = (*(DWORD *)pbBuffer); dwCRC = dwCRC ^ CrcTableOffset56[ dw2nd32 & 0x000000FF] ^ CrcTableOffset48[(dw2nd32 >> 8) & 0x000000FF] ^ CrcTableOffset40[(dw2nd32 >> 16) & 0x000000FF] ^ CrcTableOffset32[(dw2nd32 >> 24) & 0x000000FF]; pbBuffer += 4; } for(i=0; i < cbEndUnalignedBytes; ++i) dwCRC = CrcTableOffset32[(dwCRC ^ *pbBuffer++) & 0x000000FF] ^ (dwCRC >> 8); return dwCRC; } ``` -------------------------------- ### Creating PSTFile from path and buffer with error handling Source: https://github.com/epfromer/pst-extractor/blob/master/_autodocs/api-reference/PSTFile.md Demonstrates creating a PSTFile from a filesystem path and from an in-memory Buffer, then accessing the message store display name. Also shows catching the invalid header error when opening a non-PST file. ```typescript import { PSTFile } from 'pst-extractor' import * as fs from 'fs' // (a) from a path const pstFile = new PSTFile('/path/to/mail.pst') // (b) from an in-memory buffer const bufferFile = new PSTFile(fs.readFileSync('/path/to/mail.ost')) console.log(pstFile.getMessageStore().displayName) try { new PSTFile('/path/to/not-a-pst.txt') } catch (err) { // Error: PSTFile::open Invalid file header (expected: "!BDN"): ... } ``` -------------------------------- ### PSTTask Source: https://github.com/epfromer/pst-extractor/blob/master/_autodocs/api-reference/PSTTask.md Documentation for the PSTTask class, including constructor, properties, methods, and usage example. ```APIDOC ## PSTTask ### Description Task item accessor (message class `IPM.Task`). All named task properties are resolved through the name-to-ID map under `PSTFile.PSETID_Task`. Extends `PSTMessage` and inherits every `PSTMessage` member. ### Module `src/PSTTask.class.ts` ### Import Path `import { PSTTask } from 'pst-extractor'` ### Constructor ```ts constructor( pstFile: PSTFile, descriptorIndexNode: DescriptorIndexNode, table?: PSTTableBC, localDescriptorItems?: Map ) ``` Same contract as `PSTMessage`'s constructor; `(table, localDescriptorItems)` pre-population is optional. Normally obtained from `PSTFolder.getNextChild()` / `PSTUtil.detectAndLoadPSTObject`. ### Properties (getters) | Property | Type | Description | |-----------|------|-------------| | `taskStatus` | `number` | `PidLidTaskStatus` — status of the user's progress on the task. | | `percentComplete` | `number` | `PidLidPercentComplete` — progress (double; see `PSTObject.getDoubleItem`). | | `taskDateCompleted` | `Date \| null` | `PidLidTaskDateCompleted` — completion date. | | `taskActualEffort` | `number` | `PidLidTaskActualEffort` — minutes actually worked. | | `taskEstimatedEffort` | `number` | `PidLidTaskEstimatedEffort` — expected minutes. | | `taskVersion` | `number` | `PidLidTaskVersion` — latest-update indicator. | | `isTaskComplete` | `boolean` | `PidLidTaskComplete` — task is complete. | | `taskOwner` | `string` | `PidLidTaskOwner`. | | `taskAssigner` | `string` | `PidLidTaskAssigner` — last assigner. | | `taskLastUser` | `string` | `PidLidTaskLastUser` — most recent owner. | | `taskOrdinal` | `number` | `PidLidTaskOrdinal` — custom-sort aid. | | `isTaskRecurring` | `boolean` | `PidLidTaskFRecurring`. | | `taskRecurrencePattern` | `RecurrencePattern \| null` | `PidLidTaskRecurrence` — parsed via `new RecurrencePattern(blob)`. | | `taskDeadOccurrence` | `boolean` | `PidLidTaskDeadOccurrence`. | | `taskOwnership` | `number` | `PidLidTaskOwnership` — role of the current user. | | `acceptanceState` | `number` | `PidLidTaskAcceptanceState`. | ### Methods #### `toJSON(): any` ```ts public toJSON(): any ``` Returns a clone with `messageClass`, `subject`, `importance`, `transportMessageHeaders` plus all of the task getters above (recurrence pattern not included). ### Example ```ts import { PSTFile, PSTFolder, PSTTask } from 'pst-extractor' const pstFile = new PSTFile('tasks.pst') const folder = pstFile.getRootFolder() let item: any = folder.getNextChild() while (item) { if (item instanceof PSTTask) { console.log( `${item.subject} | status=${item.taskStatus} | done=${item.isTaskComplete} | ` + `${item.percentComplete * 100}%` ) if (item.taskRecurrencePattern) { const p = item.taskRecurrencePattern console.log(' recurring every', p.period, 'days, from', p.startDate, 'to', p.endDate) } } item = folder.getNextChild() } pstFile.close() ``` ### Related - `PSTMessage` — base class - `RecurrencePattern` — returned by `taskRecurrencePattern` - `types.md` — `PidLidTask*` property IDs in `OutlookProperties` ``` -------------------------------- ### Example: Using PSTObject helpers on PSTFolder Source: https://github.com/epfromer/pst-extractor/blob/master/_autodocs/api-reference/PSTObject.md Shows how PSTObject's helpers surface on a subclass like PSTFolder, including accessing displayName and getNodeType, and directly loading a PSTObject from a descriptor node. ```typescript // PSTObject is abstract — this shows how its helpers surface on a subclass const folder: PSTFolder = pstFile.getRootFolder() console.log(folder.displayName) // PSTObject.displayName console.log(folder.getNodeType()) // PSTUtil.NID_TYPE_NORMAL_FOLDER for a real folder // Direct use of the descriptor-node payload import { PSTUtil } from 'pst-extractor/dist/PSTUtil.class' const reloaded = PSTUtil.detectAndLoadPSTObject(pstFile, folder.descriptorNodeId) ``` -------------------------------- ### detectAndLoadPSTObject usage example Source: https://github.com/epfromer/pst-extractor/blob/master/_autodocs/api-reference/PSTUtil.md Example usage of detectAndLoadPSTObject with a Long descriptor id. The returned object type depends on the NID type. ```ts const obj = PSTUtil.detectAndLoadPSTObject(pstFile, Long.fromNumber(1234)) // obj may be PSTFolder | PSTMessage | PSTContact | PSTAppointment | PSTTask | PSTActivity ``` -------------------------------- ### PSTFile Constructor Source: https://github.com/epfromer/pst-extractor/blob/master/_autodocs/api-reference/PSTFile.md Constructor for the PSTFile class, which opens a PST/OST file from a filesystem path or an in-memory Buffer, validates the header, and initializes the name-to-ID map. ```APIDOC ## Constructor ```ts public constructor(pstBuffer: Buffer) public constructor(fileName: string) public constructor(arg: any) ``` ### Parameters | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | `arg` (`pstBuffer` overload) | `Buffer` | yes (one of the two overloads) | — | A `Buffer` holding the full PST/OST content, read entirely into memory. The file is served from this buffer instead of the filesystem. | | `arg` (`fileName` overload) | `string` | yes | — | Filesystem path to a `.pst`/`.ost` file, opened read-only via `fs.openSync(fileName, 'r')`. | ### Description Creates a new `PSTFile` instance by opening a PST/OST file from either a filesystem path or an in-memory `Buffer`. The constructor performs synchronous validation of the file header, version, and encryption type, and builds the name-to-ID map. ### Throws | Error message prefix | Condition | |---|---| | `PSTFile::open Invalid file header (expected: "!BDN"): ` | First 4 bytes are not `!BDN`. | | `PSTFile::open Unrecognised PST File version: ` | Version byte is not ANSI/UNICODE/2013_UNICODE. | | `PSTFile::open PST is encrypted` | Encryption type byte is `0x02`. | | `PSTFile::processNameToIDMap guidEntry is null` / `mapEntries is null` / `stringMapEntries is null` | Required table entries (IDs 2, 3, 4) missing from the name-to-ID map node. | ### Example ```ts import { PSTFile } from 'pst-extractor' import * as fs from 'fs' // (a) from a path const pstFile = new PSTFile('/path/to/mail.pst') // (b) from an in-memory buffer const bufferFile = new PSTFile(fs.readFileSync('/path/to/mail.ost')) console.log(pstFile.getMessageStore().displayName) try { new PSTFile('/path/to/not-a-pst.txt') } catch (err) { // Error: PSTFile::open Invalid file header (expected: "!BDN"): ... } ``` ``` -------------------------------- ### PSTActivity Source: https://github.com/epfromer/pst-extractor/blob/master/_autodocs/api-reference/PSTActivity.md Documentation for the PSTActivity class, including its constructor, properties, and methods. ```APIDOC ## PSTActivity ### Description Journal entry accessor (message class `IPM.Activity`). All journal properties are named properties resolved under `OutlookProperties.PSETID_Log`. Extends `PSTMessage`. ### Constructor ```ts constructor( pstFile: PSTFile, descriptorIndexNode: DescriptorIndexNode, table?: PSTTableBC, localDescriptorItems?: Map ) ``` Same contract as `PSTMessage`'s constructor. ### Properties (getters) | Property | Type | Description | |-----------|------|-------------| | `logType` | `string` | `PidLidLogType` — display name of the journaling application (e.g. `MSWord`). | | `logStart` | `Date \| null` | `PidLidLogStart` — journal start date/time. | | `logDuration` | `number` | `PidLidLogDuration` — duration in minutes. | | `logEnd` | `Date \| null` | `PidLidLogEnd` — journal end date/time. | | `logFlags` | `number` | `PidLidLogFlags` — metadata about the journal. | | `isDocumentPrinted` | `boolean` | `PidLidLogDocumentPrinted`. | | `isDocumentSaved` | `boolean` | `PidLidLogDocumentSaved`. | | `isDocumentRouted` | `boolean` | `PidLidLogDocumentRouted` — sent to a routing recipient. | | `isDocumentPosted` | `boolean` | `PidLidLogDocumentPosted` — sent by e-mail / posted to a server folder. | | `logTypeDesc` | `string` | `PidLidLogTypeDesc` — description of the activity. | ### Methods #### `toJSON(): any` Returns a clone with `messageClass`, `subject`, `importance`, `transportMessageHeaders` plus the journal getters above. ### Example ```ts import { PSTFile, PSTFolder, PSTActivity } from 'pst-extractor' const pstFile = new PSTFile('journal.pst') const folder = pstFile.getRootFolder() let item: any = folder.getNextChild() while (item) { if (item instanceof PSTActivity) { console.log( `${item.subject} | type=${item.logType} (${item.logTypeDesc}) | ` + `${item.logStart} → ${item.logEnd} | ${item.logDuration} min` ) } item = folder.getNextChild() } pstFile.close() ``` ``` -------------------------------- ### Example — reading an email with error handling Source: https://github.com/epfromer/pst-extractor/blob/master/_autodocs/api-reference/PSTMessage.md Example usage of PSTMessage to read emails from a PST file, including iterating through messages and handling attachments with error handling. ```APIDOC ## Example — reading an email with error handling ### Description Example TypeScript code demonstrating how to read emails from a PST file using PSTFile, PSTFolder, and PSTMessage, including attachment handling and error handling. ### Code ```ts import { PSTFile, PSTFolder, PSTMessage } from 'pst-extractor' const pstFile = new PSTFile('inbox.pst') const folder: PSTFolder = pstFile.getRootFolder() let email: PSTMessage | null = folder.getNextChild() while (email) { console.log(`[${email.messageClass}] ${email.subject} — ${email.senderName}`) if (email.hasAttachments) { try { for (let i = 0; i < email.numberOfAttachments; i++) { const a = email.getAttachment(i) console.log(' attachment:', a.longFilename || a.filename, a.filesize, 'bytes') } } catch (err) { console.error(' could not read attachments:', (err as Error).message) } } email = folder.getNextChild() } pstFile.close() ``` ``` -------------------------------- ### PSTFolder.displayName Source: https://github.com/epfromer/pst-extractor/blob/master/_autodocs/api-reference/PSTFolder.md Gets the display name of the folder. ```APIDOC ## [SDK] PSTFolder.getDisplayName() ### Description Returns the display name of the folder (inherited from PSTObject, `PR_DISPLAY_NAME`). ### Method GET ### Endpoint `PSTFolder.getDisplayName()` ### Parameters None ### Response #### Success Response - **displayName** (string) - Display name string. ### Response Example ```json { "displayName": "Inbox" } ``` ``` -------------------------------- ### Get message store and root folder from PSTFile Source: https://github.com/epfromer/pst-extractor/blob/master/_autodocs/api-reference/PSTMessageStore.md Shows how to obtain the message store immediately after opening a PST file and access its displayName and node type. Also demonstrates a robust pattern for retrieving the root folder and handling errors, with pstFile.close() in a finally block. The store is available without walking the folder hierarchy. ```ts import { PSTFile } from 'pst-extractor' const pstFile = new PSTFile('archive.pst') // The store is available right after opening — no folder walk needed. const store = pstFile.getMessageStore() console.log(store.displayName) // e.g. "Personal folders" console.log(store.getNodeType()) // node type bits of the store descriptor // Robust pattern for downstream processing: try { const root = pstFile.getRootFolder() console.log(root.hasSubfolders ? 'root has subfolders' : 'root is empty') } catch (err) { // Parsing errors propagate as plain Error instances — see errors.md console.error((err as Error).message) } finally { pstFile.close() } ``` -------------------------------- ### PSTFolder.containerFlags Source: https://github.com/epfromer/pst-extractor/blob/master/_autodocs/api-reference/PSTFolder.md Gets the container flags of the folder. ```APIDOC ## [SDK] PSTFolder.getContainerFlags() ### Description Returns the container flags (`PR_CONTAINER_FLAGS` 0x3600). ### Method GET ### Endpoint `PSTFolder.getContainerFlags()` ### Parameters None ### Response #### Success Response - **containerFlags** (number) - Container flags. ### Response Example ```json { "containerFlags": 0 } ``` ``` -------------------------------- ### Scan PST file for appointments Source: https://github.com/epfromer/pst-extractor/blob/master/_autodocs/api-reference/PSTAppointment.md This example demonstrates how to traverse a PST file's folder structure to identify and log details for all PSTAppointment items found. ```ts import { PSTFile, PSTFolder, PSTAppointment } from 'pst-extractor' const pstFile = new PSTFile('calendar.pst') const root = pstFile.getRootFolder() function scan(folder: PSTFolder): void { let item: any = folder.getNextChild() while (item) { if (item instanceof PSTAppointment) { console.log( `${item.subject} | ${item.startTime} → ${item.endTime} | ` + `busy=${item.showAsBusy} | recurring=${item.isRecurring} | at ${item.location}` ) } item = folder.getNextChild() } for (const sub of folder.getSubFolders()) scan(sub) } scan(root) pstFile.close() ```