@mdgate/email 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -0
- package/dist/email.d.ts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +6 -0
- package/dist/to-markdown.d.ts +6 -0
- package/package.json +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# @mdgate/email
|
|
2
|
+
|
|
3
|
+
Convert email messages to Markdown. Outputs GitHub-Flavored Markdown. Works in Node, Edge, and
|
|
4
|
+
browsers. No native addons.
|
|
5
|
+
|
|
6
|
+
Handles: `.eml`, `.msg`, `.mbox`, `.emlx`
|
|
7
|
+
|
|
8
|
+
## Usage
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { toMarkdown } from '@mdgate/email';
|
|
12
|
+
|
|
13
|
+
const markdown = await toMarkdown(bytes);
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Compose with other converters:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { create } from '@mdgate/core';
|
|
20
|
+
import { email } from '@mdgate/email';
|
|
21
|
+
|
|
22
|
+
const convert = create([email()]);
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Part of [mdgate converters](https://github.com/mdgate/converters); install
|
|
26
|
+
`@mdgate/converters` for every format at once.
|
package/dist/email.d.ts
ADDED
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import{hasOleMagic as X}from"@mdgate/containers";import{ConvertError as P}from"@mdgate/core";import{documentToMarkdown as $n}from"@mdgate/document";import{fileExtension as G}from"@mdgate/utils";import{hasOleMagic as Hn}from"@mdgate/containers";import{mimeAttachments as sn,mimeHeader as p,mimeTextHtml as un,mimeTextPlain as an,parseMime as fn}from"@mdgate/containers";import{emptyDocument as D}from"@mdgate/document";import{fileExtension as ln,trim as I}from"@mdgate/utils";import{mimeHeader as Z,parseXml as q}from"@mdgate/containers";import{ConvertError as K}from"@mdgate/core";import{heading as L,plain as m}from"@mdgate/document";import{Stylesheet as Q,toBlocks as nn}from"@mdgate/html";import{decode as tn,isAbsoluteUri as B,trim as k}from"@mdgate/utils";var en={linkTarget(n){if(n.length===0)return;if(n.startsWith("#")){let t=n.slice(1);return t.length>0?{type:"anchor",id:t}:void 0}if(B(n))return{type:"external",url:n};return{type:"relative",url:n}},imageSource(n){if(n.length===0)return;if(B(n))return{type:"external",url:n};return},anchorId(n){return n}};function E(n){let t=[],e=n.subject!==void 0?k(n.subject):"";if(e.length>0)t.push(L(1,[m(e)]));return _(t,"From",n.from),_(t,"To",n.to),_(t,"Cc",n.cc),_(t,"Date",n.date),t}function A(n){let t=n.map((e)=>k(e)).filter((e)=>e.length>0);if(t.length===0)return[];return[L(2,[m("Attachments")]),{type:"list",list:{marker:"bullet",start:1,items:t.map((e)=>({blocks:[{type:"paragraph",inlines:[m(e)]}],checked:void 0,markerLabel:void 0}))}}]}function T(n){let t=rn(n);if(t===void 0)return l(cn(n));b(t);let e=new Q;for(let r of t.descendantElems())if(r.local==="style")e.add(r.text());return nn(on(t),e,en)}function l(n){let e=n.replace(/\r\n/g,`
|
|
2
|
+
`).replace(/\r/g,`
|
|
3
|
+
`).split(/\n{2,}/),r=[];for(let o of e){let i=o.split(`
|
|
4
|
+
`).map((s)=>k(s));while(i.length>0&&i[0].length===0)i.shift();while(i.length>0&&i[i.length-1].length===0)i.pop();if(i.length===0)continue;let a=[];for(let s=0;s<i.length;s+=1){if(s>0)a.push({type:"lineBreak"});if(i[s].length>0)a.push(m(i[s]))}if(a.length>0)r.push({type:"paragraph",inlines:a})}return r}function d(n){let t=Z(n,"content-type"),e="utf-8";if(t!==void 0){let r=/charset\s*=\s*("?)([^";\s]+)\1/i.exec(t);if(r!==null)e=r[2]}return w(n.bytes,e)}function w(n,t){try{return tn(n,t)}catch{return new TextDecoder("utf-8",{fatal:!1}).decode(n)}}function _(n,t,e){let r=e!==void 0?k(e):"";if(r.length===0)return;n.push({type:"paragraph",inlines:[m(t),{type:"lineBreak"},m(`: ${r}`)]})}function rn(n){let t=[n,`<div>${n}</div>`];for(let e of t)try{return q(new TextEncoder().encode(e))}catch(r){if(r instanceof K&&r.code==="resourceLimit")throw r}return}function on(n){if(n.local==="body")return n;let t=n.local==="html"?n:n.childElems().find((e)=>e.local==="html");if(t!==void 0)return t.childElems().find((r)=>r.local==="body")??t;return n.childElems().find((e)=>e.local==="body")??n}function b(n){n.local=n.local.toLowerCase();for(let t of n.attrs)t.local=t.local.toLowerCase();for(let t of n.childElems())b(t)}function cn(n){return n.replace(/<[^>]*>/g," ")}function v(n,t){let e=fn(mn(n,t));if(e.contentType==="application/mbox"){let r=D();for(let o=0;o<e.parts.length;o+=1){if(o>0)r.blocks.push({type:"rule"});let i=N(e.parts[o]);r.blocks.push(...i.blocks)}return r}return N(e)}function N(n){let t=D();t.blocks.push(...E({subject:p(n,"subject"),from:p(n,"from"),to:p(n,"to"),cc:p(n,"cc"),date:p(n,"date")}));let e=un(n),r=an(n);if(e!==void 0){let i=T(d(e));if(i.length>0)t.blocks.push(...i);else if(r!==void 0)t.blocks.push(...l(d(r)))}else if(r!==void 0)t.blocks.push(...l(d(r)));else if(n.parts.length===0&&n.bytes.length>0)t.blocks.push(...l(d(n)));let o=sn(n).map((i)=>i.filename??i.contentType??"attachment");return t.blocks.push(...A(o)),t}function mn(n,t){if((t!==void 0?ln(t):void 0)!=="emlx"&&!dn(n))return n;return pn(n)}function dn(n){let t=F(n);if(!/^\d+$/.test(I(t.text)))return!1;let e=n.subarray(t.next),r=0;while(r<e.length&&(e[r]===32||e[r]===9))r+=1;return hn(e,r)}function pn(n){let t=F(n),e=Number(I(t.text));if(!Number.isSafeInteger(e)||e<0)return n;let r=t.next,o=Math.min(n.length,r+e);return n.subarray(r,o)}function F(n){let t=0;if(n.length>=3&&n[0]===239&&n[1]===187&&n[2]===191)t=3;let e=t;while(t<n.length&&n[t]!==10&&n[t]!==13)t+=1;let r=new TextDecoder("utf-8",{fatal:!1}).decode(n.subarray(e,t));if(n[t]===13)t+=1;if(n[t]===10)t+=1;return{text:r,next:t}}function hn(n,t){let e=t;while(e<n.length&&n[e]!==10&&n[e]!==13&&n[e]!==58)e+=1;if(e>=n.length||n[e]!==58||e===t)return!1;for(let r=t;r<e;r+=1){let o=n[r];if(!(o>=65&&o<=90||o>=97&&o<=122||o>=48&&o<=57||o===45))return!1}return!0}import{CompoundFile as j,hasOleMagic as gn,mimeHeader as h,parseMime as xn}from"@mdgate/containers";import{ConvertError as S}from"@mdgate/core";import{emptyDocument as _n}from"@mdgate/document";import{trim as g}from"@mdgate/utils";var kn=55,En=57,An=66,Tn=101,wn=125,Sn=3098,Cn=3103,Mn=3587,Pn=3588,Un=3590,H=4096,Rn=4115,Bn=12289,Ln=14084,bn=14087,Nn=11644473600000;function M(n){if(!gn(n))return!1;try{let t=j.open(n);for(let e of t.readRootStorage())if(y(e.name))return!0}catch{return!1}return!1}function W(n){let t;try{t=j.open(n)}catch(f){if(f instanceof S)throw f;throw S.malformed("not an Outlook message")}if(!Dn(t))throw S.unsupported("ole");let e=In(t),r=O(u(t,Sn),u(t,Cn))??O(u(t,An),u(t,Tn))??e.from,o=u(t,kn)??e.subject,i=u(t,Pn)??e.to,a=u(t,Mn)??e.cc,s=$(t,En)??$(t,Un)??e.date,c=_n();c.blocks.push(...E({subject:o,from:r,to:i,cc:a,date:s}));let x=u(t,Rn);if(x!==void 0&&g(x).length>0){let f=T(x);if(f.length>0)c.blocks.push(...f);else{let R=u(t,H);if(R!==void 0)c.blocks.push(...l(R))}}else{let f=u(t,H);if(f!==void 0)c.blocks.push(...l(f))}return c.blocks.push(...A(vn(t))),c}function Dn(n){for(let t of n.readRootStorage())if(y(t.name))return!0;return!1}function y(n){let t=n.toLowerCase();return t.startsWith("__substg1.0_")||t.startsWith("__properties_version1.0")||t.startsWith("__nameid_version1.0")||t.startsWith("__recip_version1.0_")||t.startsWith("__attach_version1.0_")}function In(n){let t=u(n,wn);if(t===void 0||g(t).length===0)return{};let e=xn(new TextEncoder().encode(`${t}\r
|
|
5
|
+
\r
|
|
6
|
+
`));return{subject:h(e,"subject"),from:h(e,"from"),to:h(e,"to"),cc:h(e,"cc"),date:h(e,"date")}}function vn(n){let t=[];for(let e of n.readRootStorage()){if(!e.name.toLowerCase().startsWith("__attach_version1.0_"))continue;let r=`${e.name}/`,o=u(n,bn,r)??u(n,Ln,r)??u(n,Bn,r);if(o!==void 0&&g(o).length>0)t.push(o);else t.push("attachment")}return t}function u(n,t,e=""){let r=`${e}__substg1.0_${z(t)}`;if(n.exists(`${r}001F`))return C(Fn(n.readStream(`${r}001F`)));if(n.exists(`${r}001E`))return C(w(n.readStream(`${r}001E`),"windows-1252"));if(n.exists(`${r}0102`))return C(w(n.readStream(`${r}0102`),"utf-8"));return}function $(n,t){let e=`__substg1.0_${z(t)}0040`;if(!n.exists(e))return;let r=n.readStream(e);if(r.length<8)return;let o=new DataView(r.buffer,r.byteOffset,r.byteLength),i=BigInt(o.getUint32(0,!0)),a=BigInt(o.getUint32(4,!0)),s=Number((i+(a<<32n))/10000n)-Nn,c=new Date(s);if(Number.isNaN(c.getTime()))return;return c.toUTCString()}function O(n,t){let e=n!==void 0?g(n):"",r=t!==void 0?g(t):"";if(e.length>0&&r.length>0&&e!==r)return`${e} <${r}>`;if(r.length>0)return r;if(e.length>0)return e;return}function Fn(n){let t=n.length;if(t>=2&&n[t-2]===0&&n[t-1]===0)t-=2;return new TextDecoder("utf-16le").decode(n.subarray(0,t))}function C(n){let t=n.indexOf("\x00");return t<0?n:n.slice(0,t)}function z(n){return n.toString(16).toUpperCase().padStart(4,"0")}function Y(n,t){if(Hn(n))return W(n);return v(n,t)}var On=new Set(["eml","msg","mbox","emlx"]);function U(){return{id:"email",sniff(n,t){if(X(n)){if(M(n))return 2;if(t?.path!==void 0&&G(t.path)==="msg")return 1;return 0}if(Wn(n))return 2;if(t?.path!==void 0&&On.has(G(t.path)??""))return 1;return 0},convert(n,t){return jn(n),{markdown:$n(Y(n,t?.path))}}}}function jn(n){if(Xn(n))throw P.unsupported("pdf");if(Vn(n))throw P.unsupported("zip");if(X(n)&&!M(n))throw P.unsupported("ole")}function Wn(n){let t=J(n);if(t=yn(n,t),zn(n,t))t=Gn(n,t);let e=Math.min(n.length,t+4096);while(t<e){let r=V(n,t,e);if(r.line===t)break;let o=Yn(n,t,r.line);if(o==="from"||o==="mime-version")return!0;t=r.next}return!1}function yn(n,t){let e=t;while(e<n.length&&n[e]>=48&&n[e]<=57)e+=1;if(e===t)return t;while(e<n.length&&(n[e]===32||n[e]===9))e+=1;if(n[e]===13)e+=1;if(n[e]===10)e+=1;else return t;return e}function zn(n,t){return t+5<=n.length&&n[t]===70&&n[t+1]===114&&n[t+2]===111&&n[t+3]===109&&n[t+4]===32}function Yn(n,t,e){let r=-1;for(let s=t;s<e;s+=1)if(n[s]===58){r=s;break}if(r<=t)return;let o=t,i=r;while(o<i&&(n[o]===32||n[o]===9))o+=1;while(i>o&&(n[i-1]===32||n[i-1]===9))i-=1;if(i<=o)return;let a="";for(let s=o;s<i;s+=1){let c=n[s];if(!(c>=65&&c<=90||c>=97&&c<=122||c>=48&&c<=57||c===45))return;a+=String.fromCharCode(c>=65&&c<=90?c+32:c)}return a}function V(n,t,e){let r=t;while(r<e&&n[r]!==10&&n[r]!==13)r+=1;let o=r;if(n[o]===13)o+=1;if(n[o]===10)o+=1;return{line:r,next:o}}function Gn(n,t){return V(n,t,n.length).next}function J(n){let t=0;if(n.length>=3&&n[0]===239&&n[1]===187&&n[2]===191)t=3;while(t<n.length){let e=n[t];if(e!==9&&e!==10&&e!==13&&e!==32)break;t+=1}return t}function Xn(n){return Jn(n,"%PDF-",J(n))}function Vn(n){return n.length>=4&&n[0]===80&&n[1]===75&&n[2]===3&&n[3]===4}function Jn(n,t,e){if(e+t.length>n.length)return!1;for(let r=0;r<t.length;r+=1)if(n[e+r]!==t.charCodeAt(r))return!1;return!0}import{create as Zn}from"@mdgate/core";var qn=Zn([U()]);function Kn(n,t){return qn(n,t)}export{Kn as toMarkdown,U as email};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type ConvertHint } from '@mdgate/core';
|
|
2
|
+
/**
|
|
3
|
+
* Convert a single file's bytes to Markdown with the email converter.
|
|
4
|
+
* `hint.path` is only a sniff hint; it is never read from disk.
|
|
5
|
+
*/
|
|
6
|
+
export declare function toMarkdown(bytes: Uint8Array, hint?: ConvertHint): Promise<string>;
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mdgate/email",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "mdgate email converter (eml, msg, mbox)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist/**/*.js",
|
|
18
|
+
"dist/**/*.d.ts"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "bun ../../scripts/build-package.ts",
|
|
22
|
+
"prepublishOnly": "bun run build"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@mdgate/containers": "0.1.0",
|
|
26
|
+
"@mdgate/core": "0.1.3",
|
|
27
|
+
"@mdgate/document": "0.1.0",
|
|
28
|
+
"@mdgate/html": "0.1.0",
|
|
29
|
+
"@mdgate/utils": "0.1.2"
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=20"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"mdgate",
|
|
39
|
+
"markdown",
|
|
40
|
+
"email",
|
|
41
|
+
"eml",
|
|
42
|
+
"msg",
|
|
43
|
+
"mbox"
|
|
44
|
+
]
|
|
45
|
+
}
|