@upyo/core 0.6.0-dev.294 → 0.6.0-dev.296
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 +15 -0
- package/dist/address.cjs +25 -13
- package/dist/address.js +25 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -71,6 +71,21 @@ const message = createMessage({
|
|
|
71
71
|
});
|
|
72
72
|
~~~~
|
|
73
73
|
|
|
74
|
+
Internationalized mailbox addresses are accepted, including UTF-8 local parts
|
|
75
|
+
and Unicode domains:
|
|
76
|
+
|
|
77
|
+
~~~~ typescript
|
|
78
|
+
const message = createMessage({
|
|
79
|
+
from: "josé@example.com",
|
|
80
|
+
to: "用户@例子.广告",
|
|
81
|
+
subject: "Hello",
|
|
82
|
+
content: { text: "Welcome!" },
|
|
83
|
+
});
|
|
84
|
+
~~~~
|
|
85
|
+
|
|
86
|
+
Support for delivering these addresses depends on the selected transport. The
|
|
87
|
+
*@upyo/smtp* transport negotiates RFC 6531 SMTPUTF8 automatically.
|
|
88
|
+
|
|
74
89
|
### Adding attachments
|
|
75
90
|
|
|
76
91
|
Attachments can be added using the standard [`File`] API:
|
package/dist/address.cjs
CHANGED
|
@@ -82,11 +82,13 @@ function isValidEmail(email) {
|
|
|
82
82
|
if (email.includes("\r") || email.includes("\n")) return false;
|
|
83
83
|
let atIndex = -1;
|
|
84
84
|
let inQuotes = false;
|
|
85
|
+
let escaped = false;
|
|
85
86
|
for (let i = 0; i < email.length; i++) {
|
|
86
87
|
const char = email[i];
|
|
87
|
-
if (char === "\"" &&
|
|
88
|
+
if (char === "\"" && !escaped) inQuotes = !inQuotes;
|
|
88
89
|
else if (char === "@" && !inQuotes) if (atIndex === -1) atIndex = i;
|
|
89
90
|
else return false;
|
|
91
|
+
escaped = char === "\\" && !escaped;
|
|
90
92
|
}
|
|
91
93
|
if (atIndex === -1) return false;
|
|
92
94
|
const localPart = email.substring(0, atIndex);
|
|
@@ -94,24 +96,34 @@ function isValidEmail(email) {
|
|
|
94
96
|
return isValidLocalPart(localPart) && isValidDomainPart(domainPart);
|
|
95
97
|
}
|
|
96
98
|
function isValidLocalPart(localPart) {
|
|
97
|
-
if (!localPart || localPart.length === 0 || localPart.
|
|
99
|
+
if (!localPart || localPart.length === 0 || new TextEncoder().encode(localPart).byteLength > 64) return false;
|
|
98
100
|
if (localPart.startsWith("\"") && localPart.endsWith("\"")) {
|
|
99
101
|
const quotedContent = localPart.slice(1, -1);
|
|
100
|
-
let
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
break;
|
|
107
|
-
}
|
|
102
|
+
for (let i = 0; i < quotedContent.length;) {
|
|
103
|
+
const codePoint = quotedContent.codePointAt(i);
|
|
104
|
+
if (codePoint == null || codePoint >= 55296 && codePoint <= 57343) return false;
|
|
105
|
+
if (codePoint > 127) {
|
|
106
|
+
i += codePoint > 65535 ? 2 : 1;
|
|
107
|
+
continue;
|
|
108
108
|
}
|
|
109
|
+
if (codePoint === 92) {
|
|
110
|
+
const escapedCodePoint = quotedContent.codePointAt(i + 1);
|
|
111
|
+
if (escapedCodePoint == null || escapedCodePoint < 32 || escapedCodePoint > 126) return false;
|
|
112
|
+
i += 2;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (codePoint < 32 || codePoint === 34 || codePoint === 92 || codePoint > 126) return false;
|
|
116
|
+
i++;
|
|
109
117
|
}
|
|
110
|
-
return
|
|
118
|
+
return true;
|
|
111
119
|
}
|
|
112
120
|
if (localPart.startsWith(".") || localPart.endsWith(".") || localPart.includes("..")) return false;
|
|
113
|
-
const
|
|
114
|
-
return
|
|
121
|
+
const asciiAtext = /^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]$/;
|
|
122
|
+
return localPart.split(".").every((atom) => atom.length > 0 && Array.from(atom).every((character) => {
|
|
123
|
+
if (asciiAtext.test(character)) return true;
|
|
124
|
+
const codePoint = character.codePointAt(0);
|
|
125
|
+
return codePoint != null && codePoint > 127 && !(codePoint >= 55296 && codePoint <= 57343);
|
|
126
|
+
}));
|
|
115
127
|
}
|
|
116
128
|
function isValidDomainPart(domainPart) {
|
|
117
129
|
if (!domainPart || domainPart.length === 0 || domainPart.length > 253) return false;
|
package/dist/address.js
CHANGED
|
@@ -81,11 +81,13 @@ function isValidEmail(email) {
|
|
|
81
81
|
if (email.includes("\r") || email.includes("\n")) return false;
|
|
82
82
|
let atIndex = -1;
|
|
83
83
|
let inQuotes = false;
|
|
84
|
+
let escaped = false;
|
|
84
85
|
for (let i = 0; i < email.length; i++) {
|
|
85
86
|
const char = email[i];
|
|
86
|
-
if (char === "\"" &&
|
|
87
|
+
if (char === "\"" && !escaped) inQuotes = !inQuotes;
|
|
87
88
|
else if (char === "@" && !inQuotes) if (atIndex === -1) atIndex = i;
|
|
88
89
|
else return false;
|
|
90
|
+
escaped = char === "\\" && !escaped;
|
|
89
91
|
}
|
|
90
92
|
if (atIndex === -1) return false;
|
|
91
93
|
const localPart = email.substring(0, atIndex);
|
|
@@ -93,24 +95,34 @@ function isValidEmail(email) {
|
|
|
93
95
|
return isValidLocalPart(localPart) && isValidDomainPart(domainPart);
|
|
94
96
|
}
|
|
95
97
|
function isValidLocalPart(localPart) {
|
|
96
|
-
if (!localPart || localPart.length === 0 || localPart.
|
|
98
|
+
if (!localPart || localPart.length === 0 || new TextEncoder().encode(localPart).byteLength > 64) return false;
|
|
97
99
|
if (localPart.startsWith("\"") && localPart.endsWith("\"")) {
|
|
98
100
|
const quotedContent = localPart.slice(1, -1);
|
|
99
|
-
let
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
if (
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
break;
|
|
106
|
-
}
|
|
101
|
+
for (let i = 0; i < quotedContent.length;) {
|
|
102
|
+
const codePoint = quotedContent.codePointAt(i);
|
|
103
|
+
if (codePoint == null || codePoint >= 55296 && codePoint <= 57343) return false;
|
|
104
|
+
if (codePoint > 127) {
|
|
105
|
+
i += codePoint > 65535 ? 2 : 1;
|
|
106
|
+
continue;
|
|
107
107
|
}
|
|
108
|
+
if (codePoint === 92) {
|
|
109
|
+
const escapedCodePoint = quotedContent.codePointAt(i + 1);
|
|
110
|
+
if (escapedCodePoint == null || escapedCodePoint < 32 || escapedCodePoint > 126) return false;
|
|
111
|
+
i += 2;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (codePoint < 32 || codePoint === 34 || codePoint === 92 || codePoint > 126) return false;
|
|
115
|
+
i++;
|
|
108
116
|
}
|
|
109
|
-
return
|
|
117
|
+
return true;
|
|
110
118
|
}
|
|
111
119
|
if (localPart.startsWith(".") || localPart.endsWith(".") || localPart.includes("..")) return false;
|
|
112
|
-
const
|
|
113
|
-
return
|
|
120
|
+
const asciiAtext = /^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]$/;
|
|
121
|
+
return localPart.split(".").every((atom) => atom.length > 0 && Array.from(atom).every((character) => {
|
|
122
|
+
if (asciiAtext.test(character)) return true;
|
|
123
|
+
const codePoint = character.codePointAt(0);
|
|
124
|
+
return codePoint != null && codePoint > 127 && !(codePoint >= 55296 && codePoint <= 57343);
|
|
125
|
+
}));
|
|
114
126
|
}
|
|
115
127
|
function isValidDomainPart(domainPart) {
|
|
116
128
|
if (!domainPart || domainPart.length === 0 || domainPart.length > 253) return false;
|