How to validate an e-mail address in swift?
Solution 1
I would use NSPredicate
:
func isValidEmail(_ email: String) -> Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let emailPred = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
return emailPred.evaluate(with: email)
}
for versions of Swift earlier than 3.0:
func isValidEmail(email: String) -> Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let emailPred = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
return emailPred.evaluate(with: email)
}
for versions of Swift earlier than 1.2:
func isValidEmail(email: String) -> Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
if let emailPred = NSPredicate(format:"SELF MATCHES %@", emailRegEx) {
return emailPred.evaluateWithObject(email)
}
return false
}
Solution 2
As a String
class extension
SWIFT 4
extension String {
func isValidEmail() -> Bool {
// here, `try!` will always succeed because the pattern is valid
let regex = try! NSRegularExpression(pattern: "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$", options: .caseInsensitive)
return regex.firstMatch(in: self, options: [], range: NSRange(location: 0, length: count)) != nil
}
}
Usage
if "rdfsdsfsdfsd".isValidEmail() {
}
Solution 3
Editing, updated for Swift 3:
func validateEmail(enteredEmail:String) -> Bool {
let emailFormat = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let emailPredicate = NSPredicate(format:"SELF MATCHES %@", emailFormat)
return emailPredicate.evaluate(with: enteredEmail)
}
Original answer for Swift 2:
func validateEmail(enteredEmail:String) -> Bool {
let emailFormat = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let emailPredicate = NSPredicate(format:"SELF MATCHES %@", emailFormat)
return emailPredicate.evaluateWithObject(enteredEmail)
}
It's working fine.
Solution 4
If you are looking for a clean and simple solution to do this, you should take a look at https://github.com/nsagora/validation-components.
It contains an email validation predicate which is easy integrate in your code:
let email = "[email protected]"
let rule = EmailValidationPredicate()
let isValidEmail = rule.evaluate(with: email)
Behind the hood it uses the RFC 5322 reg ex (http://emailregex.com):
let regex = "(?:[\\p{L}0-9!#$%\\&'*+/=?\\^_`{|}~-]+(?:\\.[\\p{L}0-9!#$%\\&'*+/=?\\^_`{|}" +
"~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\" +
"x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[\\p{L}0-9](?:[a-" +
"z0-9-]*[\\p{L}0-9])?\\.)+[\\p{L}0-9](?:[\\p{L}0-9-]*[\\p{L}0-9])?|\\[(?:(?:25[0-5" +
"]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-" +
"9][0-9]?|[\\p{L}0-9-]*[\\p{L}0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21" +
"-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"
Solution 5
NOWADAYS YOU >> MUST NOT << USE REGEX TO "VALIDATE" EMAILS. A SOLUTION IS NOW BUILT IN TO SWIFT/IOS:
There are now thousands of tutorials around on the obvious way to check emails these days:
https://multithreaded.stitchfix.com/blog/2016/11/02/email-validation-swift/
For historians looking at how it was done with regex:
The only solution:
1 - it avoids the horrific regex mistakes often seen in example code
2 - it does NOT allow ridiculous emails such as "x@x"
(If for some reason you need a solution that allows nonsense strings such as 'x@x', use another solution.)
3 - the code is extremely understandable
4 - it is KISS, reliable, and tested to destruction on commercial apps with enormous numbers of users
5 - the predicate is a global, as Apple says it must be
let __firstpart = "[A-Z0-9a-z]([A-Z0-9a-z._%+-]{0,30}[A-Z0-9a-z])?"
let __serverpart = "([A-Z0-9a-z]([A-Z0-9a-z-]{0,30}[A-Z0-9a-z])?\\.){1,5}"
let __emailRegex = __firstpart + "@" + __serverpart + "[A-Za-z]{2,8}"
let __emailPredicate = NSPredicate(format: "SELF MATCHES %@", __emailRegex)
extension String {
func isEmail() -> Bool {
return __emailPredicate.evaluate(with: self)
}
}
extension UITextField {
func isEmail() -> Bool {
return self.text?.isEmail() ?? false
}
}
It's that easy.
Explanation for anyone new to regex:
In this description, "OC" means ordinary character - a letter or a digit.
__firstpart ... has to start and end with an OC. For the characters in the middle you can have certain characters such as underscore, but the start and end have to be an OC. (However, it's ok to have only one OC and that's it, for example: [email protected])
__serverpart ... You have sections like "blah." which repeat. (Example, mail.city.fcu.edu.) The sections have to start and end with an OC, but in the middle you can also have a dash "-". It's OK to have a section which is just one OC. (Example, w.campus.edu) You can have up to five sections, you have to have one. Finally the TLD (such as .com) is strictly 2 to 8 in size . (Obviously, just change the "8" as preferred by your support department.)
IMPORTANT !
You MUST keep the predicate as a global, do not build it every time.
Note that this is the first thing Apple mentions about the whole issue in the docs.
Suggestions which do not cache the predicate are non-starters.
NOWADAYS YOU >> MUST NOT << USE REGEX TO "VALIDATE" EMAILS. A SOLUTION IS NOW BUILT IN TO SWIFT/IOS:
There are now thousands of tutorials around on the obvious way to check emails these days:
https://multithreaded.stitchfix.com/blog/2016/11/02/email-validation-swift/
giorgio.nocera
Updated on July 24, 2022Comments
-
giorgio.nocera almost 2 years
Does anyone know how to validate an e-mail address in Swift? I found this code:
- (BOOL) validEmail:(NSString*) emailString { if([emailString length]==0){ return NO; } NSString *regExPattern = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"; NSRegularExpression *regEx = [[NSRegularExpression alloc] initWithPattern:regExPattern options:NSRegularExpressionCaseInsensitive error:nil]; NSUInteger regExMatches = [regEx numberOfMatchesInString:emailString options:0 range:NSMakeRange(0, [emailString length])]; NSLog(@"%i", regExMatches); if (regExMatches == 0) { return NO; } else { return YES; } }
but I can't translate it to Swift.
-
Samuel Ev over 7 yearsWow, didn't know about emailregex.com. It is awesome!
-
Ben Sullivan over 7 yearsFinally, one that filters [email protected]
-
Fattie over 7 yearsthere are a few problems .. you can have, for example .. [email protected] with a weird dot there
-
Gunhan about 7 yearsabcd@a is passing with this regex. You should fix it.
-
ittgung over 6 yearsChanging to use the Regex from alexcristea' answer, it's perfect solution.
-
ami rt over 6 yearswhoever vote out my answer, kindly check your knowledge. I have applied this regex in many code and my friends of mine is using this regex and it works great..Before vote out my answer kindly do comment and let me know what is wrong with this regex.
-
Hugal31 over 6 yearsI think I can answer: Your regex is to simple and doesn't match the RFC. For example, emails can have quotes and even spaces in the first part! Look at haacked.com/archive/2007/08/21/…
-
ami rt over 6 yearsSorry, brother, I think you should check google email validation, there is no way to add Space in the first part of an email, and if my regex is wrong then why doesn't anyone post write and perfect regex.
-
Hugal31 over 6 yearsAccording to the RFC 5322, "Hello world!"@example.com is a valid email. Indeed, it is almost impossible to make a valid regex. Not every mail provider will stick to google email validation.
-
ami rt over 6 yearsThats what I want to listen, and thats why I mentioned in bold heading that above regex is like Google. Thanks
-
Leo Dabus about 6 yearsNote that
NSRange
length property should useString
utf16.count
instead ofcharacters.count
-
Leo Dabus about 6 yearsNote that NSRange length property should use String utf16.count instead of characters.count
-
Leo Dabus about 6 yearsNote that NSRange length property should use String utf16.count instead of characters.count
-
Leo Dabus about 6 yearsNote that NSRange length property should use String utf16.count instead of characters.count
-
Leo Dabus about 6 yearsNote that NSRange length property should use String utf16.count instead of characters.count
-
Leo Dabus about 6 yearsNote that NSRange length property should use String utf16.count instead of characters.count
-
Leo Dabus about 6 yearsNote that NSRange length property should use String utf16.count instead of characters.count
-
Duan Nguyen about 6 yearsUpdate Swift 4: extension String { public var isEmail: Bool { let dataDetector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) let firstMatch = dataDetector?.firstMatch(in: self, options: NSRegularExpression.MatchingOptions.reportCompletion, range: NSRange(location: 0, length: count)) return (firstMatch?.range.location != NSNotFound && firstMatch?.url?.scheme == "mailto") }
-
Roman almost 6 yearsDoes it support new TLDs like .engineer?
-
thetrutz almost 6 yearsWith regards to point (4): how did you test with a lot of users? Did you track the users, that could not sign up with the commercial apps, because the regex did prevent them from using their email address? The only "reasonable" should be, what the spec (RFC) specifies or if this can not be achieved, then something that is more relaxed, but covers everything from the spec. If the users are not allowed to enter x@x, they will enter some [email protected] which will pass your/any regex.
-
mAc over 5 yearsfailed if u write ".com" twice in the end. Check atleast very common cases before mentioning 100% working and TESTED
-
Anil Gupta over 5 yearsit's working with exact -- [email protected] . it's not validate abc@abc
-
Ümañg ßürmån about 4 yearsAh, Finally.. :D
-
rommex about 4 yearswhat is the point of repeating the repeated answer? which doesn't depend on any Swift 5 features
-
humblePilgrim over 3 yearsThis is an awesome answer. I was trying to validate the email id as the user types and toggle the enabled status of a button. With other regexes, the button gets enabled when i type aaa@aaa and then disabled when I add a '.' . This works as expected in my case.
-
Andy Weinstein over 3 yearsThis seems to allow a one character domain suffix which is technically legal but all of those are held by the registrar so in practice it will always be invalid.
-
Lucas Tegliabue over 3 yearsHi @Fattie, could you provide us a link where Apple explains that the predicate must be global? Thanks
-
Lucas Tegliabue over 3 yearsBut here the NSPredicate is no more global.
-
Alejandro Iván over 3 years@LucasTegliabue this is a more than two year old answer, it could be wrong nowadays.
-
The iOSDev over 3 yearsThanks for the first part with contains check and return false
-
Lucas Tegliabue over 3 yearsDoesn't change the fact that in your snippet the NSPredicate is no global. NSPredicate has the same lifecycle of the String instance, so is not global at all, or I am loosing something?
-
akashlal.com almost 3 yearsAbsolutely brilliant! While other answers resolve the validation of emails in english letters, this beast validates emails in Arabic and other languages as well. Well done!
-
andbi almost 3 yearsWarning. This doesn’t work with IDNs (international domain names)
-
Fattie almost 3 yearshi @andbi . It works absolutely perfectly with "international" domain names. Could you give a clear example of what you mean?
-
andbi almost 3 years@Fattie "user@домен.рф” for example. While absolutely valid, it doesn’t pass the validation.
-
Fattie over 2 years@andbi - that's a very reasonable point. the example given is (I'm sorry) only for english-language alphabets. you're definitely right that in many situations, the programmer would add the foreign alphabet. that is a top point, thank you for mentioning it.
-
Jano about 2 yearsNSDataDetector solutions are unreliable because they validate strings like:
mailto://www.google.com
, which is not an email. -
Jano about 2 yearsThis is easily fooled: "mailto://www.google.com".isEmail == true, but it’s not an email.
-
Jano about 2 years"mailto://www.google.com".isEmail == true, but not an email.
-
trndjc about 2 yearsEmail addresses can't start or end with dots (unless if they're in quotes) yet the link provided in your answer validates emails that start and end with dots. What am I missing?
-
Jimbo almost 2 yearsWould you mind sharing a link to the docs for where Apple states that an instance of
NSPredicate
must be global? I can't find it here. -
Aiden McCollum almost 2 yearsThis worked great for me once I added a ^ between the " and ( at the beginning!