how to go about email validation with zod?

im trying to validate emails with zod and have errors for when its required and invalid for example z .object({ email: z.email({ required_error: "Email is required.", invalid_type_error: "Email is invalid.", }), this is what im doing currently but i dont get this to show the required error when the field is blank! what am i messing up? ive looked into the docs but cant get to see the issue 🙁 in the zod docs we have this so i tried doing
z
.object({
email: z.email({
error: (issue) =>
issue.input === undefined ? "Email is required" : "Invalid email",
}),
z
.object({
email: z.email({
error: (issue) =>
issue.input === undefined ? "Email is required" : "Invalid email",
}),
but i still get the latter error instead of email is required 🙁
46 Replies
ἔρως
ἔρως4w ago
issue.input === undefined <-- are you sure this will be undefined when there's no value?
this is what im doing currently but i dont get this to show the required error when the field is blank!
are you talking about when you add a value and then delete it? or it's initial, unfilled state, like when the form is loaded?
curiousmissfox
I’m not familiar with Zod- does it validate that’s it’s a real address ? Or what does it do that a function like this cannot?
function isValidEmail(email) {
var re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return re.test(email.toLowerCase().trim());
}
function isValidEmail(email) {
var re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return re.test(email.toLowerCase().trim());
}
Jochem
Jochem4w ago
zod is a string validation library, so it doesn't actually validate the email is owned and accessible by the person signing up
ἔρως
ἔρως4w ago
it does what that regular expression does, but better that's ai generated? ive seen that exact code once today and i mean exact even has the unnecessary lowercase conversion
Ganesh
Ganesh4w ago
Why not use notEmpty for required message? z.email('inavlid email').nonEmpty('email can't be empty') Tho I guess If the issue is what epic described then it wouldn't help
ἔρως
ἔρως4w ago
the nonempty should be first, no? i presume it checks by the order you add
Ganesh
Ganesh4w ago
You would need to do z.string then i think Because z.email is the type
ἔρως
ἔρως4w ago
ive never used zod, so
Ganesh
Ganesh4w ago
No description
Ganesh
Ganesh4w ago
it catches both it seems
Ganesh
Ganesh4w ago
No description
Ganesh
Ganesh4w ago
No description
Ganesh
Ganesh4w ago
this works as it should likely the input is an empty string instead of undefined as epic said
ἔρως
ἔρως4w ago
i would assume it is null or an empty string if the value is missing however, it can also be undefined, which im not sure of
curiousmissfox
Im not sure, I plucked it out of a project i had open when I saw this; we are working with contacts data from a Google sheet, a project that 4 people are working on so im not sure who added this into the utility functions file but it looks pretty comventional. We do need the toLowerCase() as part of it is to normalize and clean the data people are manually entering into a Google Sheet. Where did you see an AI generated function that matches exactly? And still curious what Zod does that the 4 line function doesn't 😆
ἔρως
ἔρως4w ago
you don't need the lowercase for the regex but yeah, seems like a common approach
Ganesh
Ganesh4w ago
No description
Ganesh
Ganesh4w ago
zod uses this https://colinhacks.com/essays/reasonable-email-regex explanation for the regex used by default
ἔρως
ἔρως4w ago
or just use the rfc-compliant one
Mia
Mia4w ago
Like people did in the old days https://pdw.ex-parrot.com/Mail-RFC822-Address.html Right, right?? There are no compliant regular expressions for any email RFC really: https://www.regular-expressions.info/email.html Just checking if email contains @ is the best form of validation if needed, keeping it simple like one should. HTML by standard mandates this regex for form validation: https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address All browsers implement this exact one. Why doesn't Zod just use this one who knows.
ἔρως
ἔρως4w ago
the first link says this:
Mail::RFC822::Address is a Perl module to validate email addresses according to the RFC 822 grammar.
it's not fully compliant, as it describes, but for all intents and purposes it is compliant nobody uses comments in emails anyways, let alone nested comments also, the html spec offers an implementation, not the implementation
Mia
Mia4w ago
It is THE implementation pretty much, but yes, only for that specific use case of input form validation in the browser. As in this https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/html/forms/email_input_type.cc;l=46-53 Would make sense to use the same one so you don't validate it in two different ways when also relying on forms.
ἔρως
ἔρως4w ago
the spec says it is "an" implementation it's interesting that google chrome uses that implementation i mean, someone else already did the work anyways
Jochem
Jochem4w ago
even the spec specifically mentions that it isn't a complete implementation, and iirc that a complete implementation is impossible in a regex so yeah... whatever minimal effort basic regex you use that still allows sub-addressing is probably fine, and if it really matters definitely for sure send a verification email cause I can claim to own bill.gates@microsoft.com and any verification regex will say "yeah, sure, looks good to me!"
ἔρως
ἔρως4w ago
the idea of the regex is to quickly filter out any garbage inputs, like random junk
Jochem
Jochem4w ago
hence the most basic ones are just fine
ἔρως
ἔρως4w ago
yup my suggestion of using the big boy one is for zod, not for us to implement
Mia
Mia4w ago
Also webkit and firefox, firefox uses exactly the same actually because they validate in JS unlike others, there is a difference between regex engines so it is listed there only as an example with the actual grammar provided above, there isn't really a way to implement it other way in terms of behaviour because then your browser wont pass platform tests.
ἔρως
ἔρως4w ago
there is a way: a state machine php uses that approach it has it's issues, but it works
Mia
Mia4w ago
Like what regular expression engines do themeselves... In the end it should be equivalent in terms of behaviour.
ἔρως
ἔρως4w ago
not all regex engines use state machines
Mia
Mia4w ago
yes Well that above one from html spec was specifically decided to be pretty incomplete with email specs for ... reasons, there are much more complete ones for RFC5322 specifically if you need one.
ἔρως
ἔρως4w ago
it's supposed to reduce false negatives but while still being possible to be read and understood by humans
Jochem
Jochem4w ago
It's all a moot point anyway
ἔρως
ἔρως4w ago
client side validation is just a bonus and as a nice bonus, we can "validate" most used emails now-a-days the actual validation must all be done server side
Jochem
Jochem4w ago
Just do the bare minimum without blocking common things, and send a verification email
ἔρως
ἔρως4w ago
i would send an email with a verification code, as it can make the flow easier in some aspects also, android can automatically copy those codes
Mia
Mia4w ago
I would say more because so that they don't depend on other email specs as much, as that will complicate the RFC process.
ἔρως
ἔρως4w ago
that as well, but, in the end, client-side validation is just a bonus
Mia
Mia4w ago
Yes, it doesn't matter much really, unless you make it too restrictive and users start complaining. I find it pretty interesting that there is an "official email regex" at least for html input forms in browsers. Found this out by reading chromium source code originally, was amazed.
ἔρως
ἔρως4w ago
im surprised that there's a "reference" regex
Ganesh
Ganesh3w ago
Zod has the HTML5 regex but you need to explicitly state it
// Zod's default email regex
z.email();
z.email({ pattern: z.regexes.email }); // equivalent

// the regex used by browsers to validate input[type=email] fields
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/email
z.email({ pattern: z.regexes.html5Email });

// the classic emailregex.com regex (RFC 5322)
z.email({ pattern: z.regexes.rfc5322Email });

// a loose regex that allows Unicode (good for intl emails)
z.email({ pattern: z.regexes.unicodeEmail });
// Zod's default email regex
z.email();
z.email({ pattern: z.regexes.email }); // equivalent

// the regex used by browsers to validate input[type=email] fields
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/email
z.email({ pattern: z.regexes.html5Email });

// the classic emailregex.com regex (RFC 5322)
z.email({ pattern: z.regexes.rfc5322Email });

// a loose regex that allows Unicode (good for intl emails)
z.email({ pattern: z.regexes.unicodeEmail });
The blog post i linked before says that the dev choose the default regex because it rejects ridiculous emails with emojis and stuff in it. Not sure how html regex works
ἔρως
ἔρως3w ago
that is actually awesome
Mia
Mia3w ago
Nice
chikanlegbees
chikanlegbeesOP3w ago
email: z.email({
error: (issue) => (issue.input ? "Invalid email" : "Email is required"),
}),
email: z.email({
error: (issue) => (issue.input ? "Invalid email" : "Email is required"),
}),
i ended up doing this and guess it works @Ganesh @ἔρως @curiousmissfox @Mia @Jochem not sure if this is the best practice though!
ἔρως
ἔρως3w ago
i can't say i know either, but if it works then it works

Did you find this page helpful?