Skip to content

Commit b924695

Browse files
authored
Implement a schema for e-mail addresses (#4)
1 parent d310cbe commit b924695

2 files changed

Lines changed: 422 additions & 0 deletions

File tree

schemas/ietf/email/address.json

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
{
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"title": "RFC 5322 Email Address (Addr-Spec)",
4+
"description": "A specific Internet identifier that represents an e-mail box to which messages are delivered",
5+
"$comment": "https://www.rfc-editor.org/rfc/rfc5322#section-3.4.1",
6+
"examples": [
7+
"simple@example.com",
8+
"\"very.unusual.@.unusual.com\"@example.com",
9+
"user@[IPv6:2001:db8::1]",
10+
"(comment)john.smith@(comment)example.com(comment)",
11+
"jo(comment)hn@example.com",
12+
"user@[abc.def]"
13+
],
14+
"x-license": "https://github.com/sourcemeta/std/blob/main/LICENSE",
15+
"type": "string",
16+
"anyOf": [
17+
{
18+
"$comment": "Unquoted (dot-atom) local-part with dot-atom domain — both allow inline single-level comments",
19+
"pattern": "^(?:(?:[ \\t]|\\((?:[^()\\\\]|\\\\.)*\\))*)(?:[A-Za-z0-9!#$%&'*+\\/=?^_`{|}~-]+(?:(?:[ \\t]*\\((?:[^()\\\\]|\\\\.)*\\)[ \\t]*[A-Za-z0-9!#$%&'*+\\/=?^_`{|}~-]+)|(?:\\.[A-Za-z0-9!#$%&'*+\\/=?^_`{|}~-]+))*)(?:[ \\t]|\\((?:[^()\\\\]|\\\\.)*\\))*@(?:(?:[ \\t]|\\((?:[^()\\\\]|\\\\.)*\\))*(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?))(?:((?:[ \\t]|\\((?:[^()\\\\]|\\\\.)*\\))*\\.(?:[ \\t]|\\((?:[^()\\\\]|\\\\.)*\\))*(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)))*(?:[ \\t]|\\((?:[^()\\\\]|\\\\.)*\\))*$"
20+
},
21+
{
22+
"$comment": "Quoted local-part (with escapes) + dot-atom domain. Comments allowed around the quoted string and around domain labels",
23+
"pattern": "^(?:[ \\t]|\\((?:[^()\\\\]|\\\\.)*\\))*(?:\"(?:[^\"\\\\\\r]|\\\\.)*\")(?:[ \\t]|\\((?:[^()\\\\]|\\\\.)*\\))*@(?:(?:[ \\t]|\\((?:[^()\\\\]|\\\\.)*\\))*(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?))(?:((?:[ \\t]|\\((?:[^()\\\\]|\\\\.)*\\))*\\.(?:[ \\t]|\\((?:[^()\\\\]|\\\\.)*\\))*(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)))*(?:[ \\t]|\\((?:[^()\\\\]|\\\\.)*\\))*$"
24+
},
25+
{
26+
"$comment": "Unquoted local-part + domain-literal (arbitrary dtext / quoted-pairs inside brackets). Comments allowed around tokens",
27+
"pattern": "^(?:(?:[ \\t]|\\((?:[^()\\\\]|\\\\.)*\\))*)(?:[A-Za-z0-9!#$%&'*+\\/=?^_`{|}~-]+(?:(?:[ \\t]*\\((?:[^()\\\\]|\\\\.)*\\)[ \\t]*[A-Za-z0-9!#$%&'*+\\/=?^_`{|}~-]+)|(?:\\.[A-Za-z0-9!#$%&'*+\\/=?^_`{|}~-]+))*)(?:[ \\t]|\\((?:[^()\\\\]|\\\\.)*\\))*@(?:[ \\t]|\\((?:[^()\\\\]|\\\\.)*\\))*\\[(?:[^\\[\\]\\\\\\r]|\\\\.)*\\](?:[ \\t]|\\((?:[^()\\\\]|\\\\.)*\\))*$"
28+
},
29+
{
30+
"$comment": "Quoted local-part + domain-literal. Comments allowed around quoted local and around the literal",
31+
"pattern": "^(?:[ \\t]|\\((?:[^()\\\\]|\\\\.)*\\))*(?:\"(?:[^\"\\\\\\r]|\\\\.)*\")(?:[ \\t]|\\((?:[^()\\\\]|\\\\.)*\\))*@(?:[ \\t]|\\((?:[^()\\\\]|\\\\.)*\\))*\\[(?:[^\\[\\]\\\\\\r]|\\\\.)*\\](?:[ \\t]|\\((?:[^()\\\\]|\\\\.)*\\))*$"
32+
}
33+
],
34+
"not": {
35+
"anyOf": [
36+
{
37+
"$comment": "Disallow bare IPv4 address in domain (must be bracketed)",
38+
"pattern": "@([0-9]{1,3}\\.){3}[0-9]{1,3}(?:$|\\s)"
39+
},
40+
{
41+
"$comment": "Disallow IPv6 literal without brackets",
42+
"pattern": "@IPv6:"
43+
},
44+
{
45+
"$comment": "Disallow numeric-only final label (numeric TLDs like example.123)",
46+
"pattern": "@[^@\\s]*\\.\\d+(?:$|\\s)"
47+
},
48+
{
49+
"$comment": "Reject addresses that start with a single-quote delimiter",
50+
"pattern": "^'"
51+
}
52+
]
53+
},
54+
"format": "email",
55+
"minLength": 1
56+
}

0 commit comments

Comments
 (0)