How to validate an e-mail address in swift?

IosSwiftValidationEmailNsregularexpression

Ios Problem Overview


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.

Ios Solutions


Solution 1 - Ios

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 - Ios

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 - Ios

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 - Ios

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 - Ios

(Preamble. Be aware that in some cases, you can now use this solution built-in to iOS: https://multithreaded.stitchfix.com/blog/2016/11/02/email-validation-swift/ )


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.

Solution 6 - Ios

Simplest way in Swift 5

extension String {
	var isValidEmail: Bool {
		NSPredicate(format: "SELF MATCHES %@", "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}").evaluate(with: self)
	}
}

Example

"[email protected]".isValidEmail

returns...

true

Solution 7 - Ios

Here is a fuse of the two most up-voted answer with the correct regex: a String extension using predicate so you can call string.isEmail

    extension String {
        var isEmail: Bool {
           let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,20}"            
           let emailTest  = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
           return emailTest.evaluateWithObject(self)
        }
    }

Solution 8 - Ios

I would suggest using it as an extension of String:

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: length))
    
        return (firstMatch?.range.location != NSNotFound && firstMatch?.url?.scheme == "mailto")
    }

    public var length: Int {
        return self.characters.count
    }
}

And to use it:

if "[email protected]".isEmail { // true
    print("Hold the Door")
}

Solution 9 - Ios

This is the updated version for Swift 2.0 - 2.2

 var isEmail: Bool {
    do {
        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.firstMatchInString(self, options: NSMatchingOptions(rawValue: 0), range: NSMakeRange(0, self.characters.count)) != nil
    } catch {
        return false
    }
}

Solution 10 - Ios

There are a lot of right answers here, but many of the "regex" are incomplete and it can happen that an email like: "name@domain" results a valid email, but it is not. Here the complete solution:

extension String {

    var isEmailValid: Bool {
        do {
            let regex = try NSRegularExpression(pattern: "(?:[a-z0-9!#$%\\&'*+/=?\\^_`{|}~-]+(?:\\.[a-z0-9!#$%\\&'*+/=?\\^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-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]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])", options: .CaseInsensitive)
            return regex.firstMatchInString(self, options: NSMatchingOptions(rawValue: 0), range: NSMakeRange(0, self.characters.count)) != nil
        } catch {
            return false
        }
    }
}

Solution 11 - Ios

Here is a method based on rangeOfString:

class func isValidEmail(testStr:String) -> Bool {
    let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
    let range = testStr.rangeOfString(emailRegEx, options:.RegularExpressionSearch)
    return range != nil
}

Note: updated TLD length.

Here is the definitive RegEx for email as per RFC 5322, note that this is best not used because it only checks the basic syntax of email addresses and does not check is the top level domain exists.

(?:[a-z0-9!#$%&'+/=?^_{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_{|}~-]+)
|  "(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]
|  \[\x01-\x09\x0b\x0c\x0e-\x7f])")
@ (?:(?:a-z0-9?.)+a-z0-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]?|[a-z0-9-][a-z0-9]:
(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]
|  \[\x01-\x09\x0b\x0c\x0e-\x7f])+)
])

See Regular-Expressions.info for more complete information on email RegExs.

Note that no escaping as required by a language such as Objective-C or Swift.

Solution 12 - Ios

I prefer use an extension for that. Besides, this url http://emailregex.com can help you to test if regex is correct. In fact, the site offers differents implementations for some programming languages. I share my implementation for Swift 3.

extension String {
    func validateEmail() -> Bool {
        let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}"
        return NSPredicate(format: "SELF MATCHES %@", emailRegex).evaluate(with: self)
    }
}

Solution 13 - Ios

This a new version for "THE REASONABLE SOLUTION" by @Fattie, tested on Swift 4.1 in a new file called String+Email.swift:

import Foundation

extension String {
    private static let __firstpart = "[A-Z0-9a-z]([A-Z0-9a-z._%+-]{0,30}[A-Z0-9a-z])?"
    private static let __serverpart = "([A-Z0-9a-z]([A-Z0-9a-z-]{0,30}[A-Z0-9a-z])?\\.){1,5}"
    private static let __emailRegex = __firstpart + "@" + __serverpart + "[A-Za-z]{2,6}"

    public var isEmail: Bool {
        let predicate = NSPredicate(format: "SELF MATCHES %@", type(of:self).__emailRegex)
        return predicate.evaluate(with: self)
    }
}

So its usage is simple:

let str = "[email protected]"
if str.isEmail {
    print("\(str) is a valid e-mail address")
} else {
    print("\(str) is not a valid e-mail address")
}

I simply don't like to add a func to the String objects, as being an e-mail address is inherent to them (or not). So a Bool property would fit better than a func, from my understanding.

Solution 14 - Ios

For swift 2.1: this works correctly with email foo@bar

extension String {
    func isValidEmail() -> Bool {
        do {
            let regex = try NSRegularExpression(pattern: "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}", options: .CaseInsensitive)
            return regex.firstMatchInString(self, options: NSMatchingOptions(rawValue: 0), range: NSMakeRange(0, self.characters.count)) != nil
        } catch {
                return false
        }
    }
}

Solution 15 - Ios

Use of Swift 4.2

extension String {
    func isValidEmail() -> Bool {
        let regex = try? NSRegularExpression(pattern: "^(((([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$", options: .caseInsensitive)
        return regex?.firstMatch(in: self, options: [], range: NSMakeRange(0, self.count)) != nil
    }
    func isValidName() -> Bool{
        let regex = try? NSRegularExpression(pattern: "^[\\p{L}\\.]{2,30}(?: [\\p{L}\\.]{2,30}){0,2}$", options: .caseInsensitive)
        
        return regex?.firstMatch(in: self, options: [], range: NSMakeRange(0, self.count)) != nil
    } }

And used

if (textField.text?.isValidEmail())! 
    {
      // bla bla
    }
else 
    {

    }

Solution 16 - Ios

Make a simple test for a @ and . and send a confirmation email.

Consider this:

  • Half of the world uses non-ASCII characters.
  • Regexes are slow and complex. Btw check at least for char/letter/Unicode range, not az.
  • You can’t afford full validation because RFC rules and corresponding regex are too complex.

I’m using this basic check:

// similar to https://softwareengineering.stackexchange.com/a/78372/22077
import Foundation

/**
 Checks that
 - length is 254 or less (see https://stackoverflow.com/a/574698/412916)
 - there is a @ which is not the first character
 - there is a . after the @
 - there are at least 4 characters after the @
*/
func isValidEmail(email: String) -> Bool {
    guard email.count <= 254 else { 
        return false 
    }
    let pos = email.lastIndex(of: "@") ?? email.endIndex
    return (pos != email.startIndex)
        && ((email.lastIndex(of: ".") ?? email.startIndex) > pos) 
        && (email[pos...].count > 4)
}

print(isValidEmail(email: "アシッシュ@ビジネス.コム")) // true

Note that

  • It is considerably faster than regex and NSDataDetector.

  • It correctly reports the following as valid:

Håkan.Söderström@malmö.se"
[email protected]"
试@例子.测试.مثال.آزمایشی"
[email protected]"
[email protected]
  • It incorrectly reports the following as invalid –because they are actually valid but likely the product of a user error:
a @ b
a@b

Related:

Solution 17 - Ios

@JeffersonBe's answer is close, but returns true if the string is "something containing [email protected] a valid email" which is not what we want. The following is an extension on String that works well (and allows testing for valid phoneNumber and other data detectors to boot.

/// Helper for various data detector matches.
/// Returns `true` iff the `String` matches the data detector type for the complete string.
func matchesDataDetector(type: NSTextCheckingResult.CheckingType, scheme: String? = nil) -> Bool {
	let dataDetector = try? NSDataDetector(types: type.rawValue)
	guard let firstMatch = dataDetector?.firstMatch(in: self, options: NSRegularExpression.MatchingOptions.reportCompletion, range: NSRange(location: 0, length: length)) else {
		return false
	}
	return firstMatch.range.location != NSNotFound
		// make sure the entire string is an email, not just contains an email
		&& firstMatch.range.location == 0
		&& firstMatch.range.length == length
		// make sure the link type matches if link scheme
		&& (type != .link || scheme == nil || firstMatch.url?.scheme == scheme)
}
/// `true` iff the `String` is an email address in the proper form.
var isEmail: Bool {
	return matchesDataDetector(type: .link, scheme: "mailto")
}
/// `true` iff the `String` is a phone number in the proper form.
var isPhoneNumber: Bool {
	return matchesDataDetector(type: .phoneNumber)
}
/// number of characters in the `String` (required for above).
var length: Int {
	return self.characters.count
}

Solution 18 - Ios

Create simple extension:

extension NSRegularExpression {
    
    convenience init(pattern: String) {
        try! self.init(pattern: pattern, options: [])
    }
}

extension String {

    var isValidEmail: Bool {
        return isMatching(expression: NSRegularExpression(pattern: "^[A-Z0-9a-z\\._%+-]+@([A-Za-z0-9-]+\\.)+[A-Za-z]{2,4}$"))
    }

    //MARK: - Private

    private func isMatching(expression: NSRegularExpression) -> Bool {
        return expression.numberOfMatches(in: self, range: NSRange(location: 0, length: characters.count)) > 0
    }
}

Example:

"[email protected]".isValidEmail //true
"b@bb".isValidEmail //false

You can extend following extension to anything you need: isValidPhoneNumber, isValidPassword etc...

Solution 19 - Ios

I made a library designed for input validations and one of the "modules" allows you to easily validate a bunch of stuff...

For example to validate an email:

let emailTrial = Trial.Email
let trial = emailTrial.trial()

if(trial(evidence: "[email protected]")) {
   //email is valid
}

SwiftCop is the library... hope it help!

Solution 20 - Ios

Updated answer @Arsonik answer to Swift 2.2, using less verbose code than other offered solutions:

extension String {
    func isValidEmail() -> Bool {
        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?.firstMatchInString(self, options: [], range: NSMakeRange(0, self.characters.count)) != nil
    }
}

Solution 21 - Ios

Here is an extension in Swift 3

extension String {
    func isValidEmail() -> Bool {
        let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
        return NSPredicate(format: "SELF MATCHES %@", emailRegex).evaluate(with: self)
    }
}

Just use it like this:

if yourEmailString.isValidEmail() {
    //code for valid email address
} else {
    //code for not valid email address
}
    

Solution 22 - Ios

In Swift 4.2 and Xcode 10.1

//Email validation
func isValidEmail(email: String) -> Bool {
    let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"
    var valid = NSPredicate(format: "SELF MATCHES %@", emailRegex).evaluate(with: email)
    if valid {
        valid = !email.contains("Invalid email id")
    }
    return valid
}

//Use like this....
let emailTrimmedString = emailTF.text?.trimmingCharacters(in: .whitespaces)
if isValidEmail(email: emailTrimmedString!) == false {
   SharedClass.sharedInstance.alert(view: self, title: "", message: "Please enter valid email")
}

If you want to use SharedClass.

//This is SharedClass
import UIKit
class SharedClass: NSObject {
    
static let sharedInstance = SharedClass()

//Email validation
func isValidEmail(email: String) -> Bool {
    let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"
    var valid = NSPredicate(format: "SELF MATCHES %@", emailRegex).evaluate(with: email)
    if valid {
        valid = !email.contains("Invalid email id")
    }
    return valid
}

private override init() {
    
}
}

And call function like this....

if SharedClass.sharedInstance. isValidEmail(email: emailTrimmedString!) == false {
   SharedClass.sharedInstance.alert(view: self, title: "", message: "Please enter correct email")
   //Your code here
} else {
   //Code here
}

Solution 23 - Ios

Here's an up to date playground compatible version that uses the standard library so you don't have to maintain a regex:

import Foundation

func isValid(email: String) -> Bool {
  do {
    let detector = try NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
    let range = NSRange(location: 0, length: email.count)
    let matches = detector.matches(in: email, options: .anchored, range: range)
    guard matches.count == 1 else { return false }
    return matches[0].url?.scheme == "mailto"
  } catch {
    return false
  }
}

extension String {
  var isValidEmail: Bool {
    isValid(email: self)
  }
}

let email = "[email protected]"
isValid(email: email) // prints 'true'
email.isValidEmail // prints 'true'

Solution 24 - Ios

There are three RFCs that lay down the foundation for the "Internet Message Format".

  1. RFC 822
  2. RFC 2822 (Supersedes RFC 822)
  3. RFC 5322 (Supersedes RFC 2822)

The RFC 5322, however, defines the e-mail IDs and their naming structure in the most technical manner. That is more suitable laying down the foundation an Internet Standard that liberal enough to allow all the use-cases yet, conservative enough to bind it in some formalism.

However, the e-mail validation requirement from the software developer community, has the following needs -

  • to stave off unwanted spammers
  • to ensure the user does not make inadvertent mistake
  • to ensure that the e-mail ID belongs to the actual person inputting it

They are not exactly interested in implementing a technically all-encompassing definition that allows all the forms (IP addresses, including port IDs and all) of e-mail id. The solution suitable for their use-case is expected to solely ensure that all the legitimate e-mail holders should be able to get through. The definition of "legitimate" differs vastly from technical stand-point (RFC 5322 way) to usability stand-point(this solution). The usability aspect of the validation aims to ensure that all the e-mail IDs validated by the validation mechanism belong to actual people, using them for their communication purposes. This, thus introduces another angle to the validation process, ensuring an actually "in-use" e-mail ID, a requirement for which RFC-5322 definition is clearly not sufficient.

Thus, on practical grounds, the actual requirements boil down to this -

  1. To ensure some very basic validation checks
  2. To ensure that the inputted e-mail is in use

Second requirement typically involves, sending a standard response seeking e-mail to the inputted e-mail ID and authenticating the user based on the action delineated in the response mechanism. This is the most widely used mechanism to ensure the second requirement of validating an "in use" e-mail ID. This does involve round-tripping from the back-end server implementation and is not a straight-forward single-screen implementaion, however, one cannot do away with this.

The first requirement, stems from the need that the developers do not want totally "non e-mail like" strings to pass as an e-mail. This typically involves blanks, strings without "@" sign or without a domain name. Given the punycode representations of the domain names, if one needs to enable domain validation, they need to engage in full-fledged implementation that ensures a valid domain name. Thus, given the basic nature of requirement in this regard, validating for "<something>@<something>.<something>" is the only apt way of satisfying the requirement.

A typical regex that can satisfy this requirement is: ^[^@\s]+@[^@\s.]+.[^@\s.]+$ The above regex, follows the standard Perl regular-expression standard, widely followed by majority of the programming languages. The validation statement is: <anything except whitespaces and "@" sign>@<anything except whitespaces and "@" sign>.<anything except whitespaces, @ sign and dot>

For those who want to go one step deeper into the more relevant implementations, they can follow the following validation methodology. <e-mail local part>@<domain name>

For <e-mail local part> - Follow the guidelines by the "Universal Acceptance Steering Group" - UASG-026 For <domain name>, you can follow any domain validation methodology using standard libraries, depending on your programming language. For the recent studies on the subject, follow the document UASG-018A.

Those who are interested to know the overall process, challenges and issues involved while implementing the Internationalized Email Solution, they can also go through the following RFCs:

RFC 6530 (Overview and Framework for Internationalized Email) RFC 6531 (SMTP Extension for Internationalized Email) RFC 6532 (Internationalized Email Headers) RFC 6533 (Internationalized Delivery Status and Disposition Notifications) RFC 6855 (IMAP Support for UTF-8) RFC 6856 (Post Office Protocol Version 3 (POP3) Support for UTF-8) RFC 6857 (Post-Delivery Message Downgrading for Internationalized Email Messages) RFC 6858 (Simplified POP and IMAP Downgrading for Internationalized Email).

Solution 25 - Ios

Since there are so many weird top level domain name now, I stop checking the length of the top domain...

Here is what I use:

extension String {

    func isEmail() -> Bool {
        let emailRegEx = "^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$"
        return NSPredicate(format:"SELF MATCHES %@", emailRegEx).evaluateWithObject(self)
    } 
}

Solution 26 - Ios

Seems to work too...

let regex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"

func validate(email: String) -> Bool {
    let matches = email.rangeOfString(regex, options: .RegularExpressionSearch)
    if let _ = matches {
        return true
    }
    return false
}

Solution 27 - Ios

And for Swift 3:

extension String {
    func isValidEmail() -> Bool {
        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: NSMakeRange(0, self.characters.count)) != nil
    }
}

Solution 28 - Ios

My only addition to the list of responses would be that for Linux, NSRegularExpression does not exist, it's actually RegularExpression

    func isEmail() -> Bool {
    
    let patternNormal = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}"
    
    #if os(Linux)
        let regex = try? RegularExpression(pattern: patternNormal, options: .caseInsensitive)
    #else
        let regex = try? NSRegularExpression(pattern: patternNormal, options: .caseInsensitive)
    #endif
    
    return regex?.firstMatch(in: self, options: [], range: NSMakeRange(0, self.characters.count)) != nil

This compiles successfully on both macOS & Ubuntu.

Solution 29 - Ios

Perfect Regex like Google Email

"^[A-Z0-9a-z][a-zA-Z0-9_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"

Solution 30 - Ios

Best solution with best result for

> Swift 4.x

 extension String {
        
        func validateAsEmail() -> Bool {
            let emailRegEx = "(?:[a-zA-Z0-9!#$%\\&‘*+/=?\\^_`{|}~-]+(?:\\.[a-zA-Z0-9!#$%\\&'*+/=?\\^_`{|}" +
                "~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\" +
                "x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-" +
                "z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-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]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21" +
            "-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"
            
            let emailTest = NSPredicate(format:"SELF MATCHES[c] %@", emailRegEx)
            return emailTest.evaluate(with: self)
        }
    }

Solution 31 - Ios

I improved @Azik answer. I allow more special characters which are allowed by guidelines, as well as return a few extra edge cases as invalid.

The group think going on here to only allow ._%+- in the local part is not correct per guidelines. See @Anton Gogolev answer on this question or see below:

> The local-part of the email address may use any of these ASCII > characters: > >

> - uppercase and lowercase Latin letters A to Z and a to z;

> - digits 0 to 9;

> - special characters !#$%&'*+-/=?^_`{|}~;

> - dot ., provided that it is not the first or last character unless quoted, and provided also that it does not appear consecutively unless quoted (e.g. [email protected] is not allowed but "John..Doe"@example.com is allowed);

> - space and "(),:;<>@[\] characters are allowed with > restrictions (they are only allowed inside a quoted string, as > described in the paragraph below, and in addition, a backslash or > double-quote must be preceded by a backslash); > comments are allowed

> - with parentheses at either end of the local-part; e.g. > john.smith(comment)@example.com and (comment)[email protected] > are both equivalent to [email protected];

The code I use will not allow restricted out of place special characters, but will allow many more options than the majority of answers here. I would prefer more relaxed validation to error on the side of caution.

if enteredText.contains("..") || enteredText.contains("@@") 
   || enteredText.hasPrefix(".") || enteredText.hasSuffix(".con"){
       return false
}

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: enteredText)

Solution 32 - Ios

Generically speaking, for all programming languages: "Validating" an e-mail address with a reg-ex is something that any internet based service provider should desist from.

The possibilities of kinds of domain names and e-mail addresses have increased so much in terms of variety, any attempt at validation, which is not well thought may end up denying some valid users into your system.

To avoid this, one of the best ways is to send an email to the user and verify it being received. The good folks at "Universal Acceptance Steering Group" have compiled a languagewise list of libraries which are found to be compliant/non-compliant with various parameters involving validations vis-a-vis Internationalized Domain Names and Internationalized Email addresses. Please find the links to those documents over here and here.

Speaking specifically of SWIFT: Unfortunately, none of the validation libraries in SWIFT are compliant with the IDN Aware validation.

Solution 33 - Ios

Majority of the above regex examples fail to catch error when there are even basic problems with emails. For example

  1. [email protected] - consecutive dots
  2. [email protected] - dot after @
  3. [email protected] - dot before @
  4. [email protected] - starts with a dot

Here is a string extension I have used that uses regex with tighter rules.

extension String {
    func isValidEmail() -> Bool {
        let emailRegEx = "^(?!\\.)([A-Z0-9a-z_%+-]?[\\.]?[A-Z0-9a-z_%+-])+@[A-Za-z0-9-]{1,20}(\\.[A-Za-z0-9]{1,15}){0,10}\\.[A-Za-z]{2,20}$"
        let emailPred = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
        return emailPred.evaluate(with: self)
   }
}

Here is how we can write test case for it.

XCTAssertFalse("[email protected]".isValidEmail())
XCTAssertTrue("[email protected]".isValidEmail())

Solution 34 - Ios

Or you can have extension for optional text of UITextField:

how to use:

if  emailTextField.text.isEmailValid() {
      print("email is valid")
}else{
      print("wrong email address")
}

extension:

extension Optional where Wrapped == String {
    func isEmailValid() -> Bool{
        guard let email = self else { return false }
        let emailPattern = "[A-Za-z-0-9.-_]+@[A-Za-z0-9]+\\.[A-Za-z]{2,3}"
        do{
            let regex = try NSRegularExpression(pattern: emailPattern, options: .caseInsensitive)
            let foundPatters = regex.numberOfMatches(in: email, options: .anchored, range: NSRange(location: 0, length: email.count))
            if foundPatters > 0 {
                return true
            }
        }catch{
            //error
        }
        return false
    }
}

Solution 35 - Ios

For anyone who is still looking for an answer to this, please have a look at the following framework;

ATGValidator

It is a rule based validation framework, which handles most of the validations out of box. And top it all, it has form validator which supports validation of multiple textfields at the same time.

For validating an email string, use the following;

"[email protected]".satisfyAll(rules: [StringRegexRule.email]).status

If you want to validate an email from textfield, try below code;

textfield.validationRules = [StringRegexRule.email]
textfield.validationHandler = { result in
    // This block will be executed with relevant result whenever validation is done.
    print(result.status, result.errors)
}
// Below line is to manually trigger validation.
textfield.validateTextField()

If you want to validate it while typing in textfield or when focus is changed to another field, add one of the following lines;

textfield.validateOnInputChange(true)
// or
textfield.validateOnFocusLoss(true)

Please check the readme file at the link for more use cases.

Solution 36 - Ios

//Email validation
func validateEmail(enterEmail: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:enterEmail)
}

100% working and tested

Solution 37 - Ios

I like to create extension

   extension String {

func isValidateEmail() -> 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: self)
}

}

usage:

if emailid.text!.isValidateEmail() == false(){
 //do what ever you want if string is not matched.

}

Solution 38 - Ios

Swift 5

 func isValidEmailAddress(emailAddressString: String) -> Bool {
    
 var returnValue = true
 let emailRegEx = "[A-Z0-9a-z.-_]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,3}"
   
 do {
        let regex = try NSRegularExpression(pattern: emailRegEx)
        let nsString = emailAddressString as NSString
        let results = regex.matches(in: emailAddressString, range: NSRange(location: 0, length: nsString.length))
        
        if results.count == 0
        {
            returnValue = false
        }
        
    } catch let error as NSError {
        print("invalid regex: \(error.localizedDescription)")
        returnValue = false
    }
    
    return  returnValue
}

Then:

let validEmail = isValidEmailAddress(emailAddressString: "[email protected]")
print(validEmail)

Solution 39 - Ios

Swift 5 - Scalable Validation Layer

Using this layer you will get amazing validations over any text field easily.

Just follow the following process.

1. Add these enums:

import Foundation

enum ValidatorType
{
    case email
    case name
    // add more cases ...
}

enum ValidationError: Error, LocalizedError
{
    case invalidUserName
    case invalidEmail
    // add more cases ...

    var localizedDescription: String
    {
        switch self
        {
        case .invalidEmail:
            return "Please kindly write a valid email"    
        case .invalidUserName:
            return "Please kindly write a valid user name"
        }
    }
}

2. Add this functionality to String:

extension String
{
    // MARK:- Properties

    var isValidEmail: 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: self)
    }

    // MARK:- Methods

    func validatedText(_ validationType: ValidatorType) throws
    {
        switch validationType
        {
            case .name:
                try validateUsername()
            case .email:
                try validateEmail()
        }
    }

    // MARK:- Private Methods

    private func validateUsername() throws
    {
        if isEmpty
        {
            throw ValidationError.invalidUserName
        }
    }

    private func validateEmail() throws
    {
        if !isValidEmail 
        {
            throw ValidationError.invalidEmail
        }

        // add more validations if you want like empty email
    }
}

3. Add the following functionality to UITextField:

import UIKit

extension UITextField
{
    func validatedText(_ validationType: ValidatorType) throws
    {
        do
        {
            try text?.validatedText(validationType)
        }
        catch let validationError
        {
            shake()
            throw validationError
        }
    }

    // MARK:- Private Methods

    private func shake()
    {
        let animation = CABasicAnimation(keyPath: "position")
        animation.duration = 0.1
        animation.repeatCount = 5
        animation.fromValue = NSValue(cgPoint: CGPoint(x: center.x + 6, y: center.y))
        animation.toValue = NSValue(cgPoint: CGPoint(x: center.x - 6, y: center.y))
        layer.add(animation, forKey: "position")
    }
}

Usage

import UIKit

class LoginVC: UIViewController
{
    // MARK: Outlets

    @IBOutlet weak var textFieldEmail: UITextField!

    // MARK: View Controller Life Cycle

    override func viewDidLoad()
    {
        super.viewDidLoad()
    }

    // MARK: Methods

    private func checkEmail() -> Bool
    {
        do
        {
            try textFieldEmail.validatedText(.email)
        }
        catch let error
        {
            let validationError = error as! ValidationError
            // show alert to user with: validationError.localizedDescription
            return false
        }

        return true
    }

    // MARK: Actions

    @IBAction func loginTapped(_ sender: UIButton)
    {
        if checkEmail()
        {
            let email = textFieldEmail.text!
            // move safely ...
        }
    }
}

Solution 40 - Ios

Here is a very simple way available in current Swiftmailer. Most of the other answers are old and reinvent the wheel.

As per Swiftmailer documentation: https://swiftmailer.symfony.com/docs/messages.html#quick-reference

use Egulias\EmailValidator\EmailValidator;
use Egulias\EmailValidator\Validation\RFCValidation;

$validator = new EmailValidator();
$validator->isValid("[email protected]", new RFCValidation()); //true

This is by far the simplest and most robust approach, imo. Just install via Composer the Egulias\EmailValidator library which should already be brought in as a dependency of SwiftMailer anyway.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGiorgio NoceraView Question on Stackoverflow
Solution 1 - IosMaxim ShoustinView Answer on Stackoverflow
Solution 2 - IosArsonikView Answer on Stackoverflow
Solution 3 - IosNazikView Answer on Stackoverflow
Solution 4 - IosalexcristeaView Answer on Stackoverflow
Solution 5 - IosFattieView Answer on Stackoverflow
Solution 6 - IosKen MuellerView Answer on Stackoverflow
Solution 7 - IosNicolas ManziniView Answer on Stackoverflow
Solution 8 - IosJeffersonBeView Answer on Stackoverflow
Solution 9 - IosJoel García VerásticaView Answer on Stackoverflow
Solution 10 - IosAndrea.FerrandoView Answer on Stackoverflow
Solution 11 - IoszaphView Answer on Stackoverflow
Solution 12 - IosMarlon RuizView Answer on Stackoverflow
Solution 13 - IosAlejandro IvánView Answer on Stackoverflow
Solution 14 - Ioslee5783View Answer on Stackoverflow
Solution 15 - IosikbalView Answer on Stackoverflow
Solution 16 - IosJanoView Answer on Stackoverflow
Solution 17 - IosGujaminView Answer on Stackoverflow
Solution 18 - IosBartłomiej SemańczykView Answer on Stackoverflow
Solution 19 - IosAndresView Answer on Stackoverflow
Solution 20 - IosMatias SeijasView Answer on Stackoverflow
Solution 21 - IosGefilte FishView Answer on Stackoverflow
Solution 22 - IosNareshView Answer on Stackoverflow
Solution 23 - IosFeroView Answer on Stackoverflow
Solution 24 - IosThinkTransView Answer on Stackoverflow
Solution 25 - Iossnowmen10View Answer on Stackoverflow
Solution 26 - IosLogicopolisView Answer on Stackoverflow
Solution 27 - IosDaniView Answer on Stackoverflow
Solution 28 - IosAndrei PopaView Answer on Stackoverflow
Solution 29 - Iosami rtView Answer on Stackoverflow
Solution 30 - IosAbdelahad DarwishView Answer on Stackoverflow
Solution 31 - IosJavaBeastView Answer on Stackoverflow
Solution 32 - IosThinkTransView Answer on Stackoverflow
Solution 33 - IosHassaan FayyazView Answer on Stackoverflow
Solution 34 - IosMaciej ChrzastekView Answer on Stackoverflow
Solution 35 - IosSuranView Answer on Stackoverflow
Solution 36 - IosMr.Javed MultaniView Answer on Stackoverflow
Solution 37 - Iossiva kumarView Answer on Stackoverflow
Solution 38 - IosArafin RussellView Answer on Stackoverflow
Solution 39 - IosEssam FahmiView Answer on Stackoverflow
Solution 40 - IosJaneDoeView Answer on Stackoverflow