Fix Resend ValidationError by adding email validation (#12511)

Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
Graham Neubig
2026-02-08 06:47:39 -08:00
committed by GitHub
parent 0d13c57d9f
commit c4a90b1f89
2 changed files with 150 additions and 0 deletions

View File

@@ -26,6 +26,7 @@ Optional environment variables:
"""
import os
import re
import sys
import time
from typing import Any, Dict, List, Optional
@@ -90,6 +91,31 @@ class ResendAPIError(ResendSyncError):
pass
# Email validation regex pattern - matches standard email format
# This pattern is intentionally strict to avoid Resend API validation errors
# It rejects special characters like ! that some email providers technically allow
# but Resend's API does not accept
EMAIL_REGEX = re.compile(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$')
def is_valid_email(email: str) -> bool:
"""Validate an email address format.
This uses a regex pattern that matches most valid email addresses
while rejecting addresses with special characters that Resend's API
does not accept (e.g., exclamation marks).
Args:
email: The email address to validate.
Returns:
True if the email is valid, False otherwise.
"""
if not email:
return False
return bool(EMAIL_REGEX.match(email))
def get_keycloak_users(offset: int = 0, limit: int = 100) -> List[Dict[str, Any]]:
"""Get users from Keycloak using the admin client.
@@ -336,6 +362,7 @@ def sync_users_to_resend():
'total_users': total_users,
'existing_contacts': len(resend_contacts),
'added_contacts': 0,
'skipped_invalid_emails': 0,
'errors': 0,
}
@@ -355,6 +382,12 @@ def sync_users_to_resend():
logger.debug(f'User {email} already exists in Resend, skipping')
continue
# Validate email format before attempting to add to Resend
if not is_valid_email(email):
logger.warning(f'Skipping user with invalid email format: {email}')
stats['skipped_invalid_emails'] += 1
continue
try:
first_name = user.get('first_name')
last_name = user.get('last_name')

View File

@@ -0,0 +1,117 @@
"""Tests for resend_keycloak email validation."""
from sync.resend_keycloak import is_valid_email
class TestIsValidEmail:
"""Test cases for is_valid_email function."""
def test_valid_simple_email(self):
"""Test that a simple valid email passes validation."""
assert is_valid_email('user@example.com') is True
def test_valid_email_with_plus(self):
"""Test that email with + modifier passes validation."""
assert is_valid_email('user+tag@example.com') is True
def test_valid_email_with_dots(self):
"""Test that email with dots in local part passes validation."""
assert is_valid_email('first.last@example.com') is True
def test_valid_email_with_numbers(self):
"""Test that email with numbers passes validation."""
assert is_valid_email('user123@example.com') is True
def test_valid_email_with_subdomain(self):
"""Test that email with subdomain passes validation."""
assert is_valid_email('user@mail.example.com') is True
def test_valid_email_with_hyphen_domain(self):
"""Test that email with hyphen in domain passes validation."""
assert is_valid_email('user@example-site.com') is True
def test_valid_email_with_underscore(self):
"""Test that email with underscore passes validation."""
assert is_valid_email('user_name@example.com') is True
def test_valid_email_with_percent(self):
"""Test that email with percent sign passes validation."""
assert is_valid_email('user%name@example.com') is True
def test_invalid_email_with_exclamation(self):
"""Test that email with exclamation mark fails validation.
This is the specific case from the bug report:
ethanjames3713+!@gmail.com
"""
assert is_valid_email('ethanjames3713+!@gmail.com') is False
def test_invalid_email_with_special_chars(self):
"""Test that email with other special characters fails validation."""
assert is_valid_email('user!name@example.com') is False
assert is_valid_email('user#name@example.com') is False
assert is_valid_email('user$name@example.com') is False
assert is_valid_email('user&name@example.com') is False
assert is_valid_email("user'name@example.com") is False
assert is_valid_email('user*name@example.com') is False
assert is_valid_email('user=name@example.com') is False
assert is_valid_email('user^name@example.com') is False
assert is_valid_email('user`name@example.com') is False
assert is_valid_email('user{name@example.com') is False
assert is_valid_email('user|name@example.com') is False
assert is_valid_email('user}name@example.com') is False
assert is_valid_email('user~name@example.com') is False
def test_invalid_email_no_at_symbol(self):
"""Test that email without @ symbol fails validation."""
assert is_valid_email('userexample.com') is False
def test_invalid_email_no_domain(self):
"""Test that email without domain fails validation."""
assert is_valid_email('user@') is False
def test_invalid_email_no_local_part(self):
"""Test that email without local part fails validation."""
assert is_valid_email('@example.com') is False
def test_invalid_email_no_tld(self):
"""Test that email without TLD fails validation."""
assert is_valid_email('user@example') is False
def test_invalid_email_single_char_tld(self):
"""Test that email with single character TLD fails validation."""
assert is_valid_email('user@example.c') is False
def test_invalid_email_empty_string(self):
"""Test that empty string fails validation."""
assert is_valid_email('') is False
def test_invalid_email_none(self):
"""Test that None fails validation."""
assert is_valid_email(None) is False
def test_invalid_email_whitespace(self):
"""Test that email with whitespace fails validation."""
assert is_valid_email('user @example.com') is False
assert is_valid_email('user@ example.com') is False
assert is_valid_email(' user@example.com') is False
assert is_valid_email('user@example.com ') is False
def test_invalid_email_double_at(self):
"""Test that email with double @ fails validation."""
assert is_valid_email('user@@example.com') is False
def test_email_double_dot_domain(self):
"""Test email with double dot in domain.
Note: The regex allows this as it's technically valid in some edge cases,
and Resend's API may accept it. The main goal is to reject special
characters like ! that Resend definitely rejects.
"""
# This is allowed by our regex - Resend may or may not accept it
assert is_valid_email('user@example..com') is True
def test_case_insensitive_validation(self):
"""Test that validation works for uppercase emails."""
assert is_valid_email('USER@EXAMPLE.COM') is True
assert is_valid_email('User@Example.Com') is True