diff --git src/wp-includes/formatting.php src/wp-includes/formatting.php
index 58b4f9d..0532f58 100644
--- src/wp-includes/formatting.php
+++ src/wp-includes/formatting.php
@@ -2935,7 +2935,7 @@ function sanitize_option($option, $value) {
 			$value = array();
 
 			foreach ( $domains as $domain ) {
-				if ( ! preg_match( '/(--|\.\.)/', $domain ) && preg_match( '|^([a-zA-Z0-9-\.])+$|', $domain ) )
+				if ( ! preg_match( '/(--|\.\.)/', $domain ) && preg_match( '|^([a-zA-Z0-9-\.\*])+$|', $domain ) )
 					$value[] = $domain;
 			}
 			if ( ! $value )
diff --git src/wp-includes/ms-functions.php src/wp-includes/ms-functions.php
index 6620998..0955a04 100644
--- src/wp-includes/ms-functions.php
+++ src/wp-includes/ms-functions.php
@@ -373,35 +373,113 @@ function get_blog_id_from_url( $domain, $path = '/' ) {
  */
 function is_email_address_unsafe( $user_email ) {
 	$banned_names = get_site_option( 'banned_email_domains' );
-	if ( $banned_names && ! is_array( $banned_names ) )
-		$banned_names = explode( "\n", $banned_names );
 
-	$is_email_address_unsafe = false;
+	$is_email_domain_in_list = is_domain_in_list( $user_email, $banned_names );
+	/**
+	 * Filter a check for whether an email's domain is banned.
+	 *
+	 * @since 3.5.0
+	 *
+	 * @param bool $is_email_domain_in_list True if the email domain is banned.
+	 * @param string $user_email The email provided by the user at registration.
+	 */
+	return apply_filters( 'is_email_address_unsafe', $is_email_domain_in_list, $user_email );
+}
+
+/**
+ * Checks an email address against a whitelist of allowed domains.
+ *
+ * The email address is checked against the value of the 'limited_email_domains'
+ * option, which is only evaluated for self-registrations. User creation from
+ * the Network Admin bypasses this check.
+ *
+ * @since 3.7.0
+ *
+ * @param string $user_email The email provided by the user at registration.
+ * @return bool Returns true when the email address is allowed.
+ */
+function is_email_address_allowed( $user_email ) {
+	$allowed_names = get_site_option( 'limited_email_domains' );
+
+	// Any address is allowed when no whitelist is present
+	if ( empty( $allowed_names ) ) {
+		$is_email_address_allowed = true;
+	} else {
+		$is_email_address_allowed = is_domain_in_list( $user_email, $allowed_names );
+	}
+
+	/**
+	 * Filter a check for whether an email's domain is allowed via whitelist.
+	 *
+	 * @since 3.7.0
+	 *
+	 * @param bool $is_email_address_allowed True when the email address is allowed.
+	 * @param string $user_email The email provided by the user at registration.
+	 */
+	return apply_filters( 'is_email_address_allowed', $is_email_address_allowed, $user_email );
+}
+
+/**
+ * Checks whether an email or domain is on a domain whitelist/blacklist
+ *
+ * Used by is_email_address_unsafe() and is_email_address_allowed() to do
+ * a wildcard-safe check of an email against an array of allowed/banned
+ * domains.
+ *
+ * Any complete section of a URL (between the dots) can be represented by
+ * a wildcard. Eg, 'test@foo.bar.com' will count as a match for '*.bar.com'.
+ *
+ * @since 3.7.0
+ *
+ * @param string       $domain      The string being checked (email or domain).
+ * @param array|string $domain_list Domains to check against.
+ * @return bool Returns true when the email matches one of the domains on the list.
+ */
+function is_domain_in_list( $domain, $domain_list ) {
+	if ( ! is_array( $domain_list ) ) {
+		$domain_list = explode( "\n", $domain_list );
+	}
 
-	if ( $banned_names && is_array( $banned_names ) ) {
-		$banned_names = array_map( 'strtolower', $banned_names );
-		$normalized_email = strtolower( $user_email );
+	// If $domain is a full email address, parse out the domain
+	$atsign = strpos( $domain, '@' );
+	if ( false !== $atsign ) {
+		$domain = substr( $domain, $atsign + 1 );
+	}
 
-		list( $email_local_part, $email_domain ) = explode( '@', $normalized_email );
+	$is_in_list = false;
 
-		foreach ( $banned_names as $banned_domain ) {
-			if ( ! $banned_domain )
+	if ( $domain_list && is_array( $domain_list ) ) {
+		$domain_list = array_map( 'strtolower', $domain_list );
+		$domain = strtolower( $domain );
+
+		foreach ( $domain_list as $listed_domain ) {
+			if ( ! $listed_domain ) {
 				continue;
+			}
 
-			if ( $email_domain == $banned_domain ) {
-				$is_email_address_unsafe = true;
+			if ( $domain == $listed_domain ) {
+				$is_in_list = true;
 				break;
 			}
 
-			$dotted_domain = ".$banned_domain";
-			if ( $dotted_domain === substr( $normalized_email, -strlen( $dotted_domain ) ) ) {
-				$is_email_address_unsafe = true;
+			$dotted_domain = ".$listed_domain";
+			if ( $dotted_domain === substr( $domain, -strlen( $dotted_domain ) ) ) {
+				$is_in_list = true;
 				break;
 			}
+
+			if ( false !== strpos( $listed_domain, '*' ) ) {
+				$domain_pattern = '|' . str_replace( '\*', '[a-zA-Z0-9-]+', preg_quote( $listed_domain ) ) . '|';
+				preg_match( $domain_pattern, $domain, $matches );
+				if ( isset( $matches[0] ) && $matches[0] == $domain ) {
+					$is_in_list = true;
+					break;
+				}
+			}
 		}
 	}
 
-	return apply_filters( 'is_email_address_unsafe', $is_email_address_unsafe, $user_email );
+	return $is_in_list;
 }
 
 /**
@@ -470,12 +548,8 @@ function wpmu_validate_user_signup($user_name, $user_email) {
 	if ( !is_email( $user_email ) )
 		$errors->add('user_email', __( 'Please enter a valid email address.' ) );
 
-	$limited_email_domains = get_site_option( 'limited_email_domains' );
-	if ( is_array( $limited_email_domains ) && empty( $limited_email_domains ) == false ) {
-		$emaildomain = substr( $user_email, 1 + strpos( $user_email, '@' ) );
-		if ( in_array( $emaildomain, $limited_email_domains ) == false )
-			$errors->add('user_email', __('Sorry, that email address is not allowed!'));
-	}
+	if ( ! is_email_address_allowed( $user_email ) )
+		$errors->add('user_email', __( 'Sorry, that email address is not allowed!' ) );
 
 	// Check if the username has been used already.
 	if ( username_exists($user_name) )
diff --git tests/phpunit/tests/ms.php tests/phpunit/tests/ms.php
index 34c35a0..c279128 100644
--- tests/phpunit/tests/ms.php
+++ tests/phpunit/tests/ms.php
@@ -897,34 +897,58 @@ class Tests_MS extends WP_UnitTestCase {
 
 	/**
 	 * @ticket 21570
+	 * @ticket 15706
 	 */
 	function test_aggressiveness_of_is_email_address_unsafe() {
-		update_site_option( 'banned_email_domains', array( 'bar.com', 'foo.co' ) );
+		update_site_option( 'banned_email_domains', array( 'bar.com', 'foo.co', '*.foo.org', 'foo.*.gov' ) );
 
-		foreach ( array( 'test@bar.com', 'test@foo.bar.com', 'test@foo.co', 'test@subdomain.foo.co' ) as $email_address ) {
+		foreach ( array( 'test@bar.com', 'test@foo.bar.com', 'test@foo.co', 'test@subdomain.foo.co', 'test@bar.foo.org', 'test@foo.bar.gov' ) as $email_address ) {
 			$this->assertTrue( is_email_address_unsafe( $email_address ), "$email_address should be UNSAFE" );
 		}
 
-		foreach ( array( 'test@foobar.com', 'test@foo-bar.com', 'test@foo.com', 'test@subdomain.foo.com' ) as $email_address ) {
+		foreach ( array( 'test@foobar.com', 'test@foo-bar.com', 'test@foo.com', 'test@subdomain.foo.com', 'test@bar.baz.foo.org', 'test@foo.bar.baz.gov' ) as $email_address ) {
 			$this->assertFalse( is_email_address_unsafe( $email_address ), "$email_address should be SAFE" );
 		}
 	}
 
 	/**
 	 * @ticket 25046
+	 * @ticket 15706
 	 */
 	function test_case_sensitivity_of_is_email_address_unsafe() {
-		update_site_option( 'banned_email_domains', array( 'baR.com', 'Foo.co', 'barfoo.COM', 'BAZ.com' ) );
+		update_site_option( 'banned_email_domains', array( 'baR.com', 'Foo.co', 'barfoo.COM', 'BAZ.com', '*.fOo.org', 'foo.*.Gov' ) );
 
-		foreach ( array( 'test@Bar.com', 'tEst@bar.com', 'test@barFoo.com', 'tEst@foo.bar.com', 'test@baz.Com' ) as $email_address ) {
+		foreach ( array( 'test@Bar.com', 'tEst@bar.com', 'test@barFoo.com', 'tEst@foo.bar.com', 'test@baz.Com', 'test@bAR.foo.org', 'test@fOO.bar.gov' ) as $email_address ) {
 			$this->assertTrue( is_email_address_unsafe( $email_address ), "$email_address should be UNSAFE" );
 		}
 
-		foreach ( array( 'test@Foobar.com', 'test@Foo-bar.com', 'tEst@foobar.com', 'test@Subdomain.Foo.com', 'test@fooBAz.com' ) as $email_address ) {
+		foreach ( array( 'test@Foobar.com', 'test@Foo-bar.com', 'tEst@foobar.com', 'test@Subdomain.Foo.com', 'test@fooBAz.com', 'test@bar.bAZ.foo.org', 'test@foo.BAr.baz.gov' ) as $email_address ) {
 			$this->assertFalse( is_email_address_unsafe( $email_address ), "$email_address should be SAFE" );
 		}
 
 	}
+
+	/**
+	 * @ticket 15706
+	 */
+	function test_is_email_address_allowed() {
+		update_site_option( 'limited_email_domains', array( 'bar.com', 'foo.co', '*.foo.org', 'foo.*.gov' ) );
+
+		foreach ( array( 'test@bar.com', 'test@foo.co', 'test@bar.foo.org', 'test@foo.bar.gov' ) as $email_address ) {
+			$this->assertTrue( is_email_address_allowed( $email_address ), "$email_address should be SAFE" );
+ 		}
+
+ 		foreach ( array( 'test@foobar.com', 'test@foo-bar.com', 'test@foo.com', 'test@subdomain.foo.com', 'test@bar.baz.foo.org', 'test@foo.bar.baz.gov' ) as $email_address ) {
+			$this->assertFalse( is_email_address_allowed( $email_address ), "$email_address should be UNSAFE" );
+		}
+
+		update_site_option( 'limited_email_domains', '' );
+
+		foreach ( array( 'test@foobar.com', 'test@foo-bar.com', 'test@foo.com', 'test@subdomain.foo.com', 'test@bar.baz.foo.org', 'test@foo.bar.baz.gov' ) as $email_address ) {
+			$this->assertTrue( is_email_address_allowed( $email_address ), "$email_address should be SAFE" );
+		}
+	}
+
 	/**
 	 * @ticket 21552
 	 * @ticket 23418
