Or if you REALLY want a regex for an input, /[^\s]+@[^\s]+/ seems as sure as you can get without excluding a valid address somewhere. At least one non-whitespace character followed by an @ followed by at least one non-whitespace character. Any more specific than that and it's dicey.
But also just send an email instead if you need to validate the email address.
Ha, that is how I have always done it. Verify that there is at least one @ in the "address", and then send a verification email to it. The software that is most qualified to validate a user's email address, is the user's email server software. Why would I want to duplicate everything it does?
While the RFC allows a lot of weird email address edgecases, I see little reason to allow most of these when a user signs up to my service. How many legitimate users will use quoted strings, dotless domains or even IP addresses?
it implies support, and may place more burden on testing. if you test with XYZ only, but also allow ABC... then ABC stops working... you'll have pissed off customers.
Sure, but that's a different story. You might piss them off and lose customers. You may also be knowingly increasing your support costs.
For the average company trying to navigate these sorts of decisions, supporting users with emails like "a$123@1-2-3.12397.museum" probably isn't high on their list of priorities, regardless of whether it's "valid" or not.
Sure there is. It may signal more edge-case behavior to come. If you're building a developer tool, you should probably support it. But if you're building a consumer product, that may not be a customer you want.
> already in the business of hurting people, then it's a good way of identifying those you're trying to hurt
What?
Some customers cost more to serve than they will ever make you. Still serving them may make sense. But often it doesn’t. If you’re bootstrapping a gummy bear start-up, a customer who pings you weekly with edge-case support tickets is unlikely worth the engineering effort to appease. If you’re building an AWS competitor, on the other hand, you may want to hire them.
If you try to handle email precisely correctly according to the specification, you will find that users will complain that you're handling email incorrectly. The biggest aspect of this is case-sensitivity: local parts are officially case sensitive, but the overwhelming practice is that email addresses are case insensitive, and people expect to find email addresses via case-insensitive lookup.
As I say in my sibling comment, there are generally two purposes you might have with an email address. If your primary purpose is actually handling email, then that is when you need to be perfectly precise for email. But if your purpose is in using the email address as some sort of "universal internet ID"--this is true for the vast majority of uses of email addresses--then restricting the set of potentially valid email addresses is not only valid but a good idea.
Quoted string local-parts and IP address literals in lieu of domains are things which are generally broken by middleware software that deals with email addresses anyways, to such a degree that there is no way anyone who has such an email address is using it as anything other than a "do you actually support this" email address--it can't be a valid unique-ish identifier for them. Additionally, allowing them to creep into parts of your system may break assumptions of other databases, which increases the chance of weird, deep failures that may cause security vulnerabilities. That alone is a pretty good reason to block them.
The basic rule of thumb I use this: are you implementing email at the MTA level (needing to build/parse RFC 5321 commands or RFC 5322 blobs directly), or are you using email closer to a "universal internet ID" purpose (i.e., application perspective)?
If you are in the former category, then yes, follow the spec to the letter. If you're in the latter, then screw the precise guidelines of the spec and reject emails that are very unlikely to be valid: no quoted localparts, no IP address literals. In addition, go ahead and say that email is case-insensitive (more precisely, case-preserving).
Does it matter? Even if the email is a bog-standard USERNAME@gmail.com, you've got no way to know if the email is real until you send a challenge email to the address. If you have to do that anyway, why bother validating anything unnecessary?
Correct. Anytime a site ask me for an email before giving me a file, a code or download, I use something@gmail.com (the literal word something) & most of the time the site gives me what I am looking for. If they send that link in email only, then I use a temporary email.
I own a similar email address, and I have to say that I absolutely hate the people that do what you do. I can't tell you how many real services people sign up for, while using a "something@gmail.com" address. There are only a couple that include a "someone used my email address to sign up" link to remove my email from their account. Sigh.
It doesn't have to be a real domain or a potentially-valid address. I will usually use something like spam@gmail.com, root@localhost, or info@TheirWebsite.com. Last one likely gives them a taste of their own medicine.
1,2,3,14 add a lot of complexity which increases the potential for bugs and security issues.
12 is almost certainly a typo
13 is probably a spammer
Also <input type=email> will reject several of these as well, so if you have such an edge-case email in your database, you'll run into issues with html forms.
> Just send a confirmation email to whatever string they provide you.
You might want to first check that it is not a local address, and to reject it if it is (unless it is being used for an internal registration service). You should also reject it if the destination is unreachable (in which case it is not possible to send a confirmation email, anyways).
I have a TLD that is 4 letters and non-standard to the usual .com, .net, .org, or even .io addresses you see everyday. I regret it so much, because I still found places where 4-letter TLDs are flagged as invalid. Additionlly, sub-domains are often "invalid", and I use addresses like `site@subdomain.domain.weird` to keep track of who sells my information. I had to buy a .com domain to have a backup for those sites that invalidate my normal addresses. Nowdays I have started to use Fastmail's "masked email" feature for a lot of sites (so I just get `random.words1234@fastmail.com`), but that requires more config than just my usual scheme.
Single letter local part used to be a big problem, and still sometimes is, but it's getting better. Hey, Microsoft has stopped declaring my primary mail address invalid a few years ago.
I have had a similar problem with the 4 letter extension causing issues. What is really annoying is the sites that allow the signup with the 4 letters but then proceed to fail at every other opportunity up to and including opt out(GAP). I spent an hour with them over the phone before anyone even understood what I was saying.
I am also now using Fastmail addresses for anything I don't have some trust for and isn't a problem if lost. I no longer use my domain for things outside of this because it seems like an obvious step to simply link an unknown domain together, even if a laughable amount of companies don't.
I used to work at Sendmail, and the people who literally wrote Sendmail, which had to understand every possible valid email, would always repeat this mantra:
There is exactly one way to validate an email address, and that is to send it an email.
No matter what regex you use, you will be wrong. Sure, use the 800 line regex to do a pre-validation and ask the user "are you sure this is correct?" if it fails, but let them use it anyway if they click yes, because it might just be valid.
Then send it an email and if it bounces or they don't click the verification link, move on and delete it.
Yeah, but sending emails that bounce via SES or any hosted service hurts your business because it lowers your trust rating. You are expected to filter crap from reaching their servers. "But @jedberg told me the only way I could know that foo!fu*k_your-momma"<>"123:hello@fuckyou.com is an invalid email was to send to it" won't fly.
Obviously you have to take other precautions and not just blindly try to validate any email you get. But my point was you shouldn't reject an email only because it fails regex validation.
Also, those services don't ding you if you get a single bounce from a new email. They only start penalizing you if you repeatedly send to the same email and it bounces. You could always put checks in place to store previously failed email addresses.
And if your business is generating a bunch of take signups, it sounds like you need to put some rate limits on your sign up page.
And of course that's not deliverable, you can't use a : outside of a quoted part. :) But that is actually a perfect example of why you can't use a regex. Maybe they modified their mail server to accept it.
No one knows that for sure, Amazon doesn't publish how they determine what counts against you.
But from everything I've seen anecdotally, it does not. If you review the bounces and suppress the emails, it works just fine.
Getting booted for bounces really only happens to high volume senders who are using scraped lists to send cold emails. And it's mostly the complaints that ruin your reputation, not the bounces.
My problem with all these is simple: unlike dealing with people's names which, for the most part, they did not choose and have legitimate cultural reasons for the presence of special characters therein, it's not my problem if someone wants to register on my site with an (RFC-compliant!) email like @1st.relay,@2nd.relay:user@final.domain or a quoted email like (following payload is unquoted, quotes you see are part of the email address) "<>"@netmeister.org
I am going to put a (sane and reasonable) maximum length for email addresses on my postgres db column so it's not stored in TOAST; I don't care if you're technically allowed 256 bytes before the @ sign: I'm not wasting space in my database so you can feel special.
I do validate that the domain not only resolves but that it also has a valid MX record because this benefits ~100% of my users and protects them from their typos. It's not my problem if you want to register for my service before you set up your nameservers - its yours.
etc, etc, etc.
It's a fun thought experiment but there's no way in hell I'm going to advise any company to actually allow any of these and open themselves up to a can of worms.
A more sane list of rules would be things like "make sure you support - in the prefix or the domain" and others of its ilk. Also, I came across an email address that was created automatically from Active Directory to Azure with the apostrophe preserved (think "Sean O'Henry" turned into "sean.o'henry@example.com" and it blew my mind when that "just worked" in testing. These would be helpful rules because you'll actually encounter them in the real-world and not supporting them will genuinely inconvenience real people and not someone's PhD research.
> I do validate that the domain not only resolves but that it also has a valid MX record because this benefits ~100% of my users and protects them from their typos. It's not my problem if you want to register for my service before you set up your nameservers - its yours.
In absence of an MX record MTA will use an A record and a small but non-zero fraction of domains really has an A record pointing to a mail server.
Having no mx record and the domain A record pointing to a mail server is valid and is a small edge case. If one were to validate mx records for an a to spam measure using this the false positive rate would be extremely low. Really anyone not having an mx record and using the A record of the root domain I’d love to hear what you are doing. I didn’t even know this was a thing until a two years ago in a career of 20 plus years.
I did this for years with my self hosted mail server until Vimeo refused to let me register. Basically, I didn't see any reason anyone needs to know that I'm running a mail server unless they already know my address. I wondered if it might help me avoid spam. No idea whether it actually did, but I just figured it wouldn't hurt to be a little more discreet.
It's not a huge deal, but I would have preferred to continue without one.
If you want to be a little more precise, the '.' characters in the local part cannot be consecutive nor occur at the start or end of the string. Also, the syntax does not account for EAI (add any non-C1 control non-ASCII Unicode character to the list of allowable characters), nor does it account for IDN (complicated, but it's IDN, there's libraries for it).
Unfortunately, email is in a weird space where there's a lot of clearly incorrect validators out there that fail on common stuff (e.g., dashes in domain names, weird TLDs, etc.), but trying to find a good one is hard because many people want to "help" by flexing how good they are at covering really, really weird cases that you honestly shouldn't want to support, like relay routing, or RFC 822 comments in email addresses (which aren't actually part of the email address!).
Except that the HTML spec explicitly states just before that regex that what it checks is not whether it's a valid e-mail address, and that it intentionally rejects valid e-mail address.
<local portion>@<destination portion> is how I seem to remember "email address validation".
The '@' is the only reserved visible character.
The local portion is ONLY to be interpreted by the destination host.
Destination portion does not have to follow any pattern except to specify something (such as a path or resource name) findable by the mail server.
Of course, if you specify a destination only understood by your local email server as a destination in your LAN/WAN/whatever when talking to somebody/something outside that, they won't be able to reach you.
Addresses tend to look a lot more orderly than they used to, but I think this would be a "valid" address (within a given system):
Not an "instead of" approach, but the best thing I'd implemented when running an ecom site was a typo detector that prompted people to fix their email if it looked wrong, like "joe@gnail.com", "Did you mean joe@gmail.com?".
Yeah RFC says something reality is very different, allowing multiple @ in 2023 is just stupid and not how emails work, as a matter of fact gmail does not allows it.
Some email services (like Amazon SES) track your "bounce rate" and ding you on it. When you're sending too many bounces, you can have operational issues. They'll shut you off.
Sure, given a magic oracle avoiding the bounces is good. But what percentage of bad emails can be detected before testing? Especially at the level that a regular expression can detect?
The more bad thing is, where they take the one with + at sign up, but their login page throws error on email with + sign. Indian Pension Fund, a government website does it. You can signup with example+enps@anything.com but can't login. If you try to login with example@any, it will say email not found. They only way around is either go in person & submit a paper form; or signup from scratch with a new email.
It's all legacy, tech debt from the early Internet days (and before.) My first email address was through a UUCP feed, back in 1991 or so. We used bang paths. My email was something like uunet!host2!host1!username.
When validating email addresses in my Atom feed generation library, I use a "common-sense subset" of RFC 5322 [1].
If that email address validation is "wrong" anywhere in the sense of conflicting with real-world usage, it's probably mostly in not allowing UTF-8 characters in the local or domain parts. I'm guessing that for that I'll need to dig into RFC 6531 and 5890.
The article comes off as a "gotcha! Your service is broken!!" but ask any developer or product owner about this and they will simply say that they don't care about the 0.00001% of users signing up with such emails.
60 comments
[ 3.9 ms ] story [ 137 ms ] threadOr if you REALLY want a regex for an input, /[^\s]+@[^\s]+/ seems as sure as you can get without excluding a valid address somewhere. At least one non-whitespace character followed by an @ followed by at least one non-whitespace character. Any more specific than that and it's dicey.
But also just send an email instead if you need to validate the email address.
For the average company trying to navigate these sorts of decisions, supporting users with emails like "a$123@1-2-3.12397.museum" probably isn't high on their list of priorities, regardless of whether it's "valid" or not.
Sure there is. It may signal more edge-case behavior to come. If you're building a developer tool, you should probably support it. But if you're building a consumer product, that may not be a customer you want.
I pass no judgment here. I only mean to admit my incorrect assumption.
What?
Some customers cost more to serve than they will ever make you. Still serving them may make sense. But often it doesn’t. If you’re bootstrapping a gummy bear start-up, a customer who pings you weekly with edge-case support tickets is unlikely worth the engineering effort to appease. If you’re building an AWS competitor, on the other hand, you may want to hire them.
As I say in my sibling comment, there are generally two purposes you might have with an email address. If your primary purpose is actually handling email, then that is when you need to be perfectly precise for email. But if your purpose is in using the email address as some sort of "universal internet ID"--this is true for the vast majority of uses of email addresses--then restricting the set of potentially valid email addresses is not only valid but a good idea.
Quoted string local-parts and IP address literals in lieu of domains are things which are generally broken by middleware software that deals with email addresses anyways, to such a degree that there is no way anyone who has such an email address is using it as anything other than a "do you actually support this" email address--it can't be a valid unique-ish identifier for them. Additionally, allowing them to creep into parts of your system may break assumptions of other databases, which increases the chance of weird, deep failures that may cause security vulnerabilities. That alone is a pretty good reason to block them.
If you are in the former category, then yes, follow the spec to the letter. If you're in the latter, then screw the precise guidelines of the spec and reject emails that are very unlikely to be valid: no quoted localparts, no IP address literals. In addition, go ahead and say that email is case-insensitive (more precisely, case-preserving).
12 is almost certainly a typo
13 is probably a spammer
Also <input type=email> will reject several of these as well, so if you have such an edge-case email in your database, you'll run into issues with html forms.
How many legitimate users will use capital letters, which I had to add to an in-production email validator on an app with millions of MAUs?
Just send a confirmation email to whatever string they provide you.
You might want to first check that it is not a local address, and to reject it if it is (unless it is being used for an internal registration service). You should also reject it if the destination is unreachable (in which case it is not possible to send a confirmation email, anyways).
Millions?
I am also now using Fastmail addresses for anything I don't have some trust for and isn't a problem if lost. I no longer use my domain for things outside of this because it seems like an obvious step to simply link an unknown domain together, even if a laughable amount of companies don't.
There is exactly one way to validate an email address, and that is to send it an email.
No matter what regex you use, you will be wrong. Sure, use the 800 line regex to do a pre-validation and ask the user "are you sure this is correct?" if it fails, but let them use it anyway if they click yes, because it might just be valid.
Then send it an email and if it bounces or they don't click the verification link, move on and delete it.
Also, those services don't ding you if you get a single bounce from a new email. They only start penalizing you if you repeatedly send to the same email and it bounces. You could always put checks in place to store previously failed email addresses.
And if your business is generating a bunch of take signups, it sounds like you need to put some rate limits on your sign up page.
And of course that's not deliverable, you can't use a : outside of a quoted part. :) But that is actually a perfect example of why you can't use a regex. Maybe they modified their mail server to accept it.
No one knows that for sure, Amazon doesn't publish how they determine what counts against you.
But from everything I've seen anecdotally, it does not. If you review the bounces and suppress the emails, it works just fine.
Getting booted for bounces really only happens to high volume senders who are using scraped lists to send cold emails. And it's mostly the complaints that ruin your reputation, not the bounces.
I am going to put a (sane and reasonable) maximum length for email addresses on my postgres db column so it's not stored in TOAST; I don't care if you're technically allowed 256 bytes before the @ sign: I'm not wasting space in my database so you can feel special.
I do validate that the domain not only resolves but that it also has a valid MX record because this benefits ~100% of my users and protects them from their typos. It's not my problem if you want to register for my service before you set up your nameservers - its yours.
etc, etc, etc.
It's a fun thought experiment but there's no way in hell I'm going to advise any company to actually allow any of these and open themselves up to a can of worms.
A more sane list of rules would be things like "make sure you support - in the prefix or the domain" and others of its ilk. Also, I came across an email address that was created automatically from Active Directory to Azure with the apostrophe preserved (think "Sean O'Henry" turned into "sean.o'henry@example.com" and it blew my mind when that "just worked" in testing. These would be helpful rules because you'll actually encounter them in the real-world and not supporting them will genuinely inconvenience real people and not someone's PhD research.
In absence of an MX record MTA will use an A record and a small but non-zero fraction of domains really has an A record pointing to a mail server.
It's not a huge deal, but I would have preferred to continue without one.
Unfortunately, email is in a weird space where there's a lot of clearly incorrect validators out there that fail on common stuff (e.g., dashes in domain names, weird TLDs, etc.), but trying to find a good one is hard because many people want to "help" by flexing how good they are at covering really, really weird cases that you honestly shouldn't want to support, like relay routing, or RFC 822 comments in email addresses (which aren't actually part of the email address!).
[1] https://html.spec.whatwg.org/multipage/input.html#email-stat...
<local portion>@<destination portion> is how I seem to remember "email address validation".
The '@' is the only reserved visible character.
The local portion is ONLY to be interpreted by the destination host.
Destination portion does not have to follow any pattern except to specify something (such as a path or resource name) findable by the mail server.
Of course, if you specify a destination only understood by your local email server as a destination in your LAN/WAN/whatever when talking to somebody/something outside that, they won't be able to reach you.
Addresses tend to look a lot more orderly than they used to, but I think this would be a "valid" address (within a given system):
12855977.233~foo+esr@bar!baz.crunchly!test%test#test\\splat\3
At the time I used "mailcheck": https://github.com/mailcheck/mailcheck
There appears to be a more modern implementation here: https://github.com/ZooTools/email-spell-checker
It reduced the amount of badly entered emails more than any other approach I tried.
If that email address validation is "wrong" anywhere in the sense of conflicting with real-world usage, it's probably mostly in not allowing UTF-8 characters in the local or domain parts. I'm guessing that for that I'll need to dig into RFC 6531 and 5890.
[1]: https://docs.racket-lang.org/splitflap/mod-constructs.html#%...
e.g. x@familyname.com is rejected, but x+whydidyourejectthis@familyname.com works