Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for RFC6530, using it only when required. #3000

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

arnt
Copy link

@arnt arnt commented Jan 3, 2024

This adds the ability to send email to addresses like grå@grå.org, but preserves phpmailer's old behaviour for all addresses that worked before (such as info@grå.org).

There's one new validator, which is like the W3c validator, but extended to cover EAI. It's sort of based on Firefox' extension of the same validator.

Copy link
Member

@Synchro Synchro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this – SMTPUTF8 support is something that's been wanted for a while, but I've been avoiding as I have not wanted to deal with the support issues it will inevitably cause when connecting to servers that don't support it, and also because I've wanted to avoid a half-hearted solution that only supports UTF-8 in addresses, not in all headers (which is what Symfony Mailer does).

However, I'm willing to persevere with your approach, especially since you wrote tests too :)

@@ -1434,6 +1443,17 @@ public static function validateAddress($address, $patternselect = null)
'[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
$address
);
case 'eai':
/*
* This is the pattern used in the HTML5 spec for validation of 'email' type form input elements, modified to accept unicode email addresses. This is also more lenient than Firefox' html5 spec, in order to make the regex faster.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coincidentally, I wrote the pattern in the HTML5 spec!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, did you? In that case I wouldn't mind having a chat about how it might be updated to cover EAI, if you have a spare half hour sometime. That github issue isn't going anywhere.

*
* @var bool
*/
public $UseSMTPUTF8 = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One key problem that has stopped me pursuing SMTPUTF8 support in PHPMailer is that you can't tell ahead of time if the server supports it, so while you might provide UTF8 addresses that are valid during message construction, if the server doesn't support it it's not going to work. RFC6531 says the downgrade method is up to the MSA (i.e. PHPMailer), but how it should be handled is not defined, and it's not a simple problem to solve. Unfortunately the only reliable approach is to avoid using it altogether, which is where I've been sitting!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That part of 6531 is IMO not quite as well written as it could be.

When you walk through the various cases, the only one where a downgrade is both possible and better than an available alternative is MSA-time downgrade of the sender address. That's not a terribly relevant case for phpmailer (like for for mikel-mail, smtplib, javamail, or Sendgrid, Mailchimp, etc).

IMO, the kind of software that typically calls phpmailer is best served by using noreply@asciidomain as sender address and trusting the caller to supply the actually desired recipient address. Some phpmailer users might be seen as MSAs that could respond to errors by picking a different sender address, but that decision is IMO solidly outside phpmailer's scope.

Perhaps I should comment about how others do it... Ruby, Python and Java all have libraries that raise exceptions when something doesn't work. If the server refuses to play because we don't have the right password, they throw an exception. If the server won't relay because of a misconfiguration, another exception. The javamail/net-smtp/smtplib user is expected to catch the exceptions. I grepped around github to see what callers responded to those exceptions and didn't find any that distinguished between missing SMTPUTF8 and other exceptions.

So if it's bulk mail being generated from a database query, missing SMTPUTF8 will just add the relevant address to the list of undeliverable addresses. If it's a contact form, missing SMTPUTF8 will show up as the same error as if the server rejects the message (e.g., Postfix can reject unknown domains at injection time).

src/PHPMailer.php Show resolved Hide resolved
src/PHPMailer.php Outdated Show resolved Hide resolved
* Implements RFC 821: MAIL <SP> FROM:<reverse-path> <CRLF> and
* two extensions, namely XVERP and SMTPUTF8.
*
* The server's EHLO response is not checked. If use of either
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mentioned this earlier. You can check if the mail server supports an extension by looking in the SMTP::$server_caps array after EHLO has happened, like this:

array_key_exists('SMTPUTF8', $this->server_caps)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The check is easy, the next line is the question. I considered throwing an exception, but decided against it for the moment.

  • I didn't want to have SMTPUTF8 behave differently from XVERP in that function
  • Changing XVERP would change existing functionality (that noone should depend on, but...)
  • Callers can disable exceptions anyway

I could of course call setError(), like how sendCommand() would do when the MAIL FROM fails. Shall I?

test/PHPMailer/PHPMailerTest.php Outdated Show resolved Hide resolved
This adds the ability to send email to addresses like grå@grå.org, but
preserves phpmailer's old behaviour for all addresses that worked before
(such as info@grå.org).
@arnt
Copy link
Author

arnt commented Jan 17, 2024

Hi,

I force-pushed with most things fixed. Remaining issues:

  1. The code doesn't check whether SMTPUTF8 is supported before using it, to be similar to XVERT and because it doesn't make a difference (it only saves one roundtrip before throwing an exception).
  2. There's no attempt at downgrading. There can't very well be, phpmailer isn't given enough information by its caller.

I could change both of these at once… I could add a callback with which phpmailer would ask its caller to downgrade. The default value would be a function that returns <> if it's the sender and throws an exception if it's a recipient address. Of course I'd add unit tests to make sure ascii@idn works. Does that sound good do you? Do you think you might merge that?

@arnt
Copy link
Author

arnt commented Jan 17, 2024

The more I think about it, the better I like that approach.

@PrOgramm3r1
Copy link

PrOgramm3r1 commented Jan 18, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants