No, there should only be the one EmailAddress type. If it's not valid, it's not an EmailAddress.
Does having an EmailAddress type guarantee you won't accidentally accept crap? No, but when you get it wrong, you edit the validation in one place in the system.
> You check that stuff when the data enters the system.
There can be N entrypoints where data enters the system (different controllers, CLI), so you must always remember to validate emails in N places, otherwise broken data could end up being passed to business logic. Data can also be constructed inside the system. It's nice to have one centralized place where email is validated. Placing it in the constructor of a special type and using only that type for email guarantees it's impossible for business logic to receive invalid emails in principle, no matter what you do, because when an exception is thrown from a constructor no object is created at all. No object = no invalid data to deal with. You know that when you see EmailAddress (or any other type where state is validated in the constructor) it's in a valid state, there's no ambiguity, and, in my opinion, it's also more readable than just some string, the intent is clearer.
If you can construct an EmailAddress, then you have a valid EmailAddress. That's the point.
If an EmailAddress can be a valid or invalid email address, then just leave it as a String (since that can also be a valid or invalid email address).
> You check that stuff when the data enters the system.
Yes
> If that place is the EmailAddress type, then you have built your system wrong.
No
If you validate & construct an EmailAddress from another external class, that means external classes are free to bypass validation and construct an invalid EmailAddress. Putting the validation/construction inside EmailAddress lets you force construction to go via validation.
My advice: Relax and don't argue. People who don't understand that constructing an EmailAddress type is also validating the raw email string (in this case) will never understand it. They'll remain convinced for a very long time, possibly the rest of their lives, that they know better. That passing a string around is fine as long as either you always validate it everywhere (yes, kill your performance, that's smart) or that they validated it once and they pinky swear to never change the value and to always call validate before passing it into the system.
Let them find subtle errors in their programs over time, it's job security for them. They don't want to move on to new and more interesting things they just want to keep fixing the same shit for the rest of their careers.
Does having an EmailAddress type guarantee you won't accidentally accept crap? No, but when you get it wrong, you edit the validation in one place in the system.