arn-rawmime 0.0.2 → 0.0.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arn-rawmime",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "A lightweight, dependency-free raw MIME email builder with DKIM support.",
5
5
  "author": "ARNDESK",
6
6
  "type": "module",
@@ -96,15 +96,17 @@ class MimeMessage {
96
96
  currentLineLength = 0;
97
97
  }
98
98
  if (token.length > 75) {
99
- // Hard split for giant tokens
100
- const chunks = token.match(/.{1,73}/g);
101
- chunks.forEach((chunk, idx) => {
102
- if (idx < chunks.length - 1) {
103
- result += chunk + "=\r\n";
104
- } else {
105
- result += chunk;
106
- currentLineLength = chunk.length;
99
+ // Hard split for giant tokens (Atom-aware)
100
+ // Find QP sequences (=XX) or single chars to avoid breaking a triplet
101
+ const atoms = token.match(/=[0-9A-F]{2}|./g) || [];
102
+ atoms.forEach((atom) => {
103
+ // Check if adding this atom exceeds the safety limit (75 to leave room for soft break '=')
104
+ if (currentLineLength + atom.length > 75) {
105
+ result += "=\r\n";
106
+ currentLineLength = 0;
107
107
  }
108
+ result += atom;
109
+ currentLineLength += atom.length;
108
110
  });
109
111
  } else {
110
112
  result += token;
@@ -123,6 +125,32 @@ class MimeMessage {
123
125
 
124
126
  // ─── HELPER: Header Folding (RFC 5322) ──────────────────────────
125
127
  _foldHeader(name, value) {
128
+ const hasNonAscii = /[^\x00-\x7F]/.test(value);
129
+
130
+ // 1. Unstructured headers (Subject, etc) -> Full Encode
131
+ const unstructured = ["subject", "x-report-abuse", "thread-topic"];
132
+ if (hasNonAscii && unstructured.includes(name.toLowerCase())) {
133
+ const encodedValue = Buffer.from(value, "utf8").toString("base64");
134
+ return `${name}: =?UTF-8?B?${encodedValue}?=`;
135
+ }
136
+
137
+ // 2. Structured headers (From, To) -> Smart Replace
138
+ // Finds quoted strings with special chars, e.g. "René", and encodes JUST that part.
139
+ if (hasNonAscii) {
140
+ const encodedStruct = value.replace(/"([^"]*)"/g, (match, content) => {
141
+ if (/[^\x00-\x7F]/.test(content)) {
142
+ const b64 = Buffer.from(content, "utf8").toString("base64");
143
+ return `=?UTF-8?B?${b64}?=`;
144
+ }
145
+ return match;
146
+ });
147
+ // If we changed anything, return it. If not (e.g. unquoted special chars), fallback to old folding
148
+ if (encodedStruct !== value) {
149
+ return `${name}: ${encodedStruct}`;
150
+ }
151
+ }
152
+
153
+ // 3. Standard folding for ASCII-only (or unhandled) headers
126
154
  const line = `${name}: ${value}`;
127
155
  if (line.length <= 76) return line;
128
156