Opened 3 weeks ago

Last modified 3 weeks ago

#36809 assigned Cleanup/optimization

Allow EmailValidator to customize error messages depending on the part that failed validation

Reported by: Daniel E Onetti Owned by: Daniel E Onetti
Component: Core (Other) Version: dev
Severity: Normal Keywords: EmailValidator
Cc: Mike Edmunds Triage Stage: Accepted
Has patch: yes Needs documentation: yes
Needs tests: yes Patch needs improvement: yes
Easy pickings: no UI/UX: no

Description

Currently, the EmailValidator only provides the full 'value' in the params dictionary when a ValidationError is raised. However, in many use cases, developers need to customize error messages based specifically on the domain part of the email (e.g., "The domain %(domain_part)s is not allowed").

This change adds 'domain_part' to the params dictionary in EmailValidator.call, bringing it in line with how other validators provide decomposed parts of the validated value. This allows for more granular and helpful error messages for end users.

I have already prepared a patch with tests and verified that it passes all style (flake8) and functional checks.

Change History (7)

comment:1 by Kundan Yadav, 3 weeks ago

Owner: set to Kundan Yadav
Status: newassigned

comment:2 by Kundan Yadav, 3 weeks ago

hey can i work on it or is it already being worked on by you

in reply to:  description comment:3 by Natalia Bidart, 3 weeks ago

Has patch: set
Keywords: EmailValidator added
Needs documentation: set
Needs tests: set
Owner: changed from Kundan Yadav to Daniel E Onetti
Patch needs improvement: set
Triage Stage: UnreviewedAccepted
Type: UncategorizedCleanup/optimization

Hello Daniel! Thanks for the report, for taking the time to prepare a patch, and for following the contributing guide. I appreciate that.

I agree that the use case is valid and that being able to reference the domain in error messages can be genuinely useful. That said, I am not convinced that simply adding domain_part to ValidationError.params is the best fit for Django core. It solves the immediate problem, but does so in a way that feels quite specific rather than structural. It also risks committing to an API that only partially reflects how EmailValidator actually works.

Looking at the other validators in this module, there is a clear pattern of separating parsing, normalization, and validation into distinct steps or methods, even when the final error surface remains simple. EmailValidator is somewhat inconsistent here: it already decomposes the value into user and domain components, but does so inline inside __call__, with no clear extension points. Adding a single extra param addresses the symptom rather than the structure.

I think a more Django aligned approach would be to re-evaluate EmailValidator as a whole and give it clearer, overridable validation hooks, while keeping full backward compatibility. For example, introducing explicit methods like validate_recipient() and validate_domain(), called from __call__, would allow customization via subclassing without re-parsing the email or wrapping errors. The existing validate_domain_part() could be kept for compatibility and potentially deprecated later, since it currently returns a boolean.

So in short, I agree with the motivation, but I think the solution needs to be broader and more structural than the current proposal in order to align better with Django's existing validator patterns.

in reply to:  2 comment:4 by Natalia Bidart, 3 weeks ago

Replying to Kundan Yadav:

hey can i work on it or is it already being worked on by you

Hello Kundan, there is an initial PR already for this issue by Daniel, so I have re-assigned this to them,

comment:5 by Natalia Bidart, 3 weeks ago

Summary: Allow EmailValidator to return 'domain_part' in ValidationError paramsAllow EmailValidator to customize error messages depending on the part that failed validation

comment:6 by Mike Edmunds, 3 weeks ago

Cc: Mike Edmunds added

Natalia's proposal would also simplify implementation of #27029 EAI address validation. (Or help developers who need that functionality sooner subclass EmailValidator themselves.)

Django already uses "recipient" to mean a complete email address, possibly including a friendly display name (e.g., django.core.mail.EmailMessage.all_recipients()). The official RFC 5322 term for the part before the @ is local-part, but other common terms are user (e.g., existing EmailValidator code), username (e.g., Python's email.headerregistry.Address.username), or mailbox. I'd maybe go with validate_username() and validate_domain() to align with Python's email package.

Version 0, edited 3 weeks ago by Mike Edmunds (next)

comment:7 by Natalia Bidart, 3 weeks ago

Thank you Mike for the validation! I appreciate it. Your naming proposal sounds great!

Note: See TracTickets for help on using tickets.
Back to Top