diff --git a/CRM/Core/Form.php b/CRM/Core/Form.php
index 0f07bdd1496c..5478f87252a0 100644
--- a/CRM/Core/Form.php
+++ b/CRM/Core/Form.php
@@ -347,6 +347,7 @@ public function registerRules() {
       'settingPath',
       'autocomplete',
       'validContact',
+      'email',
     ];
 
     foreach ($rules as $rule) {
diff --git a/CRM/Utils/Rule.php b/CRM/Utils/Rule.php
index 9c5707925cb1..862e4603f747 100644
--- a/CRM/Utils/Rule.php
+++ b/CRM/Utils/Rule.php
@@ -639,12 +639,46 @@ public static function boolean($value) {
    *
    * @return bool
    */
-  public static function email($value) {
+  public static function email($value): bool {
+    if (function_exists('idn_to_ascii')) {
+      $parts = explode('@', $value);
+      foreach ($parts as &$part) {
+        // if the function returns FALSE then let filter_var have at it.
+        $part = self::idnToAsci($part) ?: $part;
+        if ($part === 'localhost') {
+          // if we are in a dev environment add .com to trick it into accepting localhost.
+          // this is a bit best-effort - ie we don't really care that it's in a bigger if.
+          $part .= '.com';
+        }
+      }
+      $value = implode('@', $parts);
+    }
     return (bool) filter_var($value, FILTER_VALIDATE_EMAIL);
   }
 
   /**
-   * @param $list
+   * Convert domain string to ascii.
+   *
+   * See https://lab.civicrm.org/dev/core/-/issues/2769
+   * and also discussion over in guzzle land
+   * https://github.com/guzzle/guzzle/pull/2454
+   *
+   * @param string $string
+   *
+   * @return string|false
+   */
+  private static function idnToAsci(string $string) {
+    if (!\extension_loaded('intl')) {
+      return $string;
+    }
+    if (defined('INTL_IDNA_VARIANT_UTS46')) {
+      return idn_to_ascii($string, 0, INTL_IDNA_VARIANT_UTS46);
+    }
+    return idn_to_ascii($string);
+  }
+
+  /**
+   * @param string $list
    *
    * @return bool
    */
diff --git a/tests/phpunit/CRM/Utils/RuleTest.php b/tests/phpunit/CRM/Utils/RuleTest.php
index 52c7da3faeb7..098a0fad5f36 100644
--- a/tests/phpunit/CRM/Utils/RuleTest.php
+++ b/tests/phpunit/CRM/Utils/RuleTest.php
@@ -306,7 +306,8 @@ public function testCreditCardValidation($number, $type): void {
   }
 
   /**
-   * Test cvvs
+   * Test cvvs.
+   *
    * @return array
    */
   public static function cvvs(): array {
@@ -343,4 +344,30 @@ public function testCvvRule($cvv, $type, $expected): void {
     $this->assertEquals($expected, CRM_Utils_Rule::cvv($cvv, $type));
   }
 
+  /**
+   * Test CVV rule
+   *
+   * @param string $email
+   * @param bool $expected expected outcome of the rule validation
+   *
+   * @dataProvider emails
+   */
+  public function testEmailRule(string $email, bool $expected): void {
+    $this->assertEquals($expected, CRM_Utils_Rule::email($email));
+  }
+
+  /**
+   * Test emails.
+   *
+   * @return array
+   */
+  public static function emails(): array {
+    $cases = [];
+    $cases['name.-o-.i.10@example.com'] = ['name.-o-.i.10@example.com', TRUE];
+    $cases['test@ēxāmplē.co.nz'] = ['test@ēxāmplē.co.nz', TRUE];
+    $cases['test@localhost'] = ['test@localhost', TRUE];
+    $cases['test@ēxāmplē.co'] = ['test@exāmple', FALSE];
+    return $cases;
+  }
+
 }