or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.mdmail-parser.mdsimple-parser.md

mail-parser.mddocs/

0

# Streaming Email Parsing

1

2

Low-level streaming parser class for advanced email processing scenarios where you need fine-grained control over the parsing process, event handling, and memory usage. Built on Node.js Transform streams for maximum efficiency.

3

4

## Capabilities

5

6

### MailParser Class

7

8

Transform stream class that parses email data and emits events for headers, text content, and attachments as they are processed.

9

10

```javascript { .api }

11

/**

12

* Advanced streaming email parser class

13

* @param options - Parsing configuration options

14

*/

15

class MailParser extends Transform {

16

constructor(options?: ParseOptions);

17

18

/** Parsed email headers (available after 'headers' event) */

19

headers: Map<string, any>;

20

/** Raw header lines (available after 'headers' event) */

21

headerLines: HeaderLine[];

22

/** HTML content (available after parsing completes) */

23

html?: string;

24

/** Plain text content (available after parsing completes) */

25

text?: string;

26

/** Text converted to HTML (available after parsing completes) */

27

textAsHtml?: string;

28

/** Email subject (available after 'headers' event) */

29

subject?: string;

30

/** From address (available after 'headers' event) */

31

from?: AddressObject;

32

/** To addresses (available after 'headers' event) */

33

to?: AddressObject;

34

/** CC addresses (available after 'headers' event) */

35

cc?: AddressObject;

36

/** BCC addresses (available after 'headers' event) */

37

bcc?: AddressObject;

38

/** Email date (available after 'headers' event) */

39

date?: Date;

40

/** Message ID (available after 'headers' event) */

41

messageId?: string;

42

/** List of attachments processed */

43

attachmentList: AttachmentData[];

44

}

45

```

46

47

**Usage Examples:**

48

49

```javascript

50

const { MailParser } = require('mailparser');

51

const fs = require('fs');

52

53

// Basic streaming parsing

54

const parser = new MailParser();

55

56

parser.on('headers', headers => {

57

console.log('Subject:', headers.get('subject'));

58

console.log('From:', headers.get('from'));

59

});

60

61

// Read data from the stream in object mode

62

const readData = () => {

63

let data;

64

while ((data = parser.read()) !== null) {

65

if (data.type === 'text') {

66

console.log('Text content:', data.text);

67

console.log('HTML content:', data.html);

68

}

69

70

if (data.type === 'attachment') {

71

console.log('Attachment:', data.filename);

72

console.log('Size:', data.size);

73

74

// Process attachment content

75

let chunks = [];

76

data.content.on('data', chunk => chunks.push(chunk));

77

data.content.on('end', () => {

78

const content = Buffer.concat(chunks);

79

console.log('Attachment content length:', content.length);

80

data.release(); // Must call to continue processing

81

readData(); // Continue reading after attachment is processed

82

});

83

return; // Wait for attachment to complete before reading more

84

}

85

}

86

};

87

88

parser.on('readable', readData);

89

90

parser.on('end', () => {

91

console.log('Parsing complete');

92

});

93

94

// Pipe email data to parser

95

fs.createReadStream('email.eml').pipe(parser);

96

```

97

98

### Event Handling

99

100

The MailParser class emits several events during the parsing process.

101

102

```javascript { .api }

103

// Headers event - emitted when email headers are parsed

104

on(event: 'headers', listener: (headers: Map<string, any>) => void): this;

105

106

// Header lines event - emitted with raw header data

107

on(event: 'headerLines', listener: (lines: HeaderLine[]) => void): this;

108

109

// Readable event - emitted when data is available to read

110

on(event: 'readable', listener: () => void): this;

111

112

// Stream reading method - call to get text/attachment data

113

read(): TextData | AttachmentData | null;

114

115

// End event - emitted when parsing is complete

116

on(event: 'end', listener: () => void): this;

117

118

// Error event - emitted when parsing errors occur

119

on(event: 'error', listener: (err: Error) => void): this;

120

```

121

122

### Text Data Object

123

124

Returned by the `read()` method when text content is parsed.

125

126

```javascript { .api }

127

interface TextData {

128

/** Always 'text' for text content */

129

type: 'text';

130

/** HTML version of the email content */

131

html?: string;

132

/** Plain text version of the email content */

133

text?: string;

134

/** Plain text converted to HTML format */

135

textAsHtml?: string;

136

}

137

```

138

139

### Attachment Data Object

140

141

Returned by the `read()` method for each attachment found in the email.

142

143

```javascript { .api }

144

interface AttachmentData {

145

/** Always 'attachment' for attachment data */

146

type: 'attachment';

147

/** Readable stream containing attachment content */

148

content: Stream;

149

/** MIME content type of the attachment */

150

contentType: string;

151

/** Part identifier within the email structure */

152

partId?: string;

153

/** Content-Disposition header value */

154

contentDisposition?: string;

155

/** Filename from Content-Disposition or Content-Type */

156

filename?: string;

157

/** Content-ID header value (with angle brackets) */

158

contentId?: string;

159

/** Clean Content-ID without angle brackets */

160

cid?: string;

161

/** Whether attachment is related to email content (embedded) */

162

related?: boolean;

163

/** All headers for this attachment part */

164

headers: Map<string, any>;

165

/** Content checksum (calculated after content is read) */

166

checksum?: string;

167

/** Size in bytes (calculated after content is read) */

168

size?: number;

169

/** Function to call when done processing attachment - REQUIRED */

170

release(): void;

171

}

172

```

173

174

### Advanced Methods

175

176

Additional methods available on the MailParser instance for advanced use cases.

177

178

```javascript { .api }

179

/**

180

* Update image links in HTML content using a custom replacement function

181

* @param replaceCallback - Function to generate replacement URLs

182

* @param done - Callback when processing is complete

183

*/

184

updateImageLinks(

185

replaceCallback: (attachment: AttachmentData, done: (err: Error | null, url?: string) => void) => void,

186

done: (err: Error | null, html?: string) => void

187

): void;

188

189

/**

190

* Convert plain text to HTML with link detection

191

* @param str - Plain text string to convert

192

* @returns HTML formatted string

193

*/

194

textToHtml(str: string): string;

195

196

/**

197

* Format email addresses as HTML

198

* @param addresses - Address objects to format

199

* @returns HTML formatted address string

200

*/

201

getAddressesHTML(addresses: Address[]): string;

202

203

/**

204

* Format email addresses as plain text

205

* @param addresses - Address objects to format

206

* @returns Plain text formatted address string

207

*/

208

getAddressesText(addresses: Address[]): string;

209

```

210

211

### Stream Processing Pattern

212

213

Important pattern for handling attachment streams correctly:

214

215

```javascript

216

parser.on('data', data => {

217

if (data.type === 'attachment') {

218

// Store attachment chunks

219

let chunks = [];

220

let size = 0;

221

222

data.content.on('readable', () => {

223

let chunk;

224

while ((chunk = data.content.read()) !== null) {

225

chunks.push(chunk);

226

size += chunk.length;

227

}

228

});

229

230

data.content.on('end', () => {

231

// Process complete attachment

232

const buffer = Buffer.concat(chunks);

233

console.log(`Processed ${data.filename}: ${buffer.length} bytes`);

234

235

// CRITICAL: Must call release() to continue parsing

236

data.release();

237

});

238

239

data.content.on('error', err => {

240

console.error('Attachment stream error:', err);

241

data.release(); // Release even on error

242

});

243

}

244

});

245

```

246

247

### Memory Management

248

249

For processing large emails efficiently:

250

251

```javascript

252

const parser = new MailParser({

253

checksumAlgo: 'sha256', // Use stronger checksum if needed

254

maxHtmlLengthToParse: 5 * 1024 * 1024 // Limit HTML parsing to 5MB

255

});

256

257

// Handle large attachments by streaming to disk

258

parser.on('data', data => {

259

if (data.type === 'attachment' && data.size > 10 * 1024 * 1024) {

260

// Stream large attachments directly to file system

261

const writeStream = fs.createWriteStream(`/tmp/${data.filename}`);

262

data.content.pipe(writeStream);

263

264

writeStream.on('finish', () => {

265

console.log(`Large attachment saved: ${data.filename}`);

266

data.release();

267

});

268

}

269

});

270

```