symfony: Unable to send an email: to parameter is missing (code 400).

Symfony version(s) affected

v6.4.4

Description

Sending emails no longer works without any adjustments. I retrieve the error Unable to send an email: to parameter is missing (code 400). Other having this problem?

How to reproduce

Sending e-mails via Laravel:

Mail::to('test@example.com') ->send(new OrderCreated($order));

Possible Solution

No response

Additional Context

No response

About this issue

  • Original URL
  • State: closed
  • Created 3 months ago
  • Comments: 22 (10 by maintainers)

Commits related to this issue

Most upvoted comments

Anyone looking for a Laravel workaround, you can add this to your mailgun config

		'mailgun' => [
			'transport' => 'mailgun',
			'client' => [ // this bit here
				'http_version' => '1.1',
			],
		],

I created a local HTTP/2 server with Deno to debug the request further. My findings:

  • HTTP/2 does not support chunked transfer encoding.
  • curl seems to ignore the Transfer-Encoding: chunked header in HTTP/2 mode.
  • However the request body is still encoded in chunks when using $body->bodyToIterable().
  • Thus the request body cannot be read by the HTTP/2 server.

This is the debug output from the HTTP/2 server. Note how the form data is mangled and missing the first entry (from), resulting in the Unable to send an email: from parameter is missing (code 400) error.

Request {
  method: "POST",
  url: "https://localhost:8000/",
  headers: Headers {
    "accept": "*/*",
    "accept-encoding": "gzip",
    "authorization": "Basic XXXXXX",
    "content-type": "multipart/form-data; boundary=TliGs4Sa",
    "user-agent": "Symfony HttpClient (Curl)"
  }
}
FormData {
  to: "2\r\n\r\n\r\n14\r\nrecipient@example.org\r\n2\r\n\r\n\r\nc",
  subject: "2\r\n\r\n\r\n18\r\nMailgunApiTransport test\r\n2\r\n\r\n\r\nc",
  text: "2\r\n\r\n\r\n20\r\nThis is your plain text message.\r\n2\r\n\r\n\r\nc",
  html: "2\r\n\r\n\r\n1d\r\n<p>This is your HTML message.\r\n2\r\n\r\n\r\nc",
  "h:Sender": "2\r\n\r\n\r\n1e\r\nsender@example.org\r\n2\r\n\r\n\r\ne"
}

Why did this issue arise suddenly? My guess would be that Mailgun just enabled HTTP/2 for their API endpoints. But I have no way to verify that.

So, the short-term solution would be forcing HTTP/1.1 requests for MailgunApiTransport. The long-term solution means looking into the way that Symfony uses content streaming for HTTP/2 requests via CurlHttpClient, which unfortunately is above my paygrade.


I won’t be able to create a pull request today due to time constraints, but I’ll open one tomorrow if necessary.

In a follow-up to @hdimitrov1 for Laravel users - if you’ve got an app that’s been upgraded from earlier versions of laravel, pop the client key onto the base array of config/mail.php:

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Mail Driver
    |--------------------------------------------------------------------------
    |
    */
    
    // ..
    
    'client' => [
        'http_version' => '1.1',
    ],

];

Same issue here. Started from April, 4th.

I read this issue and as @nicolas-grekas said it seems to be fixed. Maybe there is something I did not understand in the fix.

The fix should appear in the next official release. For now you can either use one of the workarounds or configure preferred-install in your project.

I found a better workaround that does not disable mail body streaming:

https://github.com/symfony/symfony/blob/524c7038065b65b91cce043e7eff31df901b71c8/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php#L63-L67

Set the HTTP version to 1.1 by adding the following option:

$response = $this->client->request('POST', 'https://' . $endpoint, [
	'auth_basic' => 'api:' . $this->key,
	'headers' => $headers,
	'body' => $body->bodyToIterable(),
	'http_version' => 1.1,
]);

So it seems the issue only occurs when the request is made with HTTP2.

I have been experiencing this problem since yesterday. But I’m not sure why it happened, if we haven’t updated dependencies and PHP version.

Turns out I was wrong and @eswinfen was onto something with the bodyToIterable() method. The request body sent to Mailgun seems to be empty.

https://github.com/symfony/symfony/blob/524c7038065b65b91cce043e7eff31df901b71c8/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php#L66

Replacing $body->bodyToIterable() with $body->bodyToString() resolves the issue and might be a temporary workaround. Just note that this will write the whole mail body to memory (including attachments!).


So further debugging revealed that Symfony does create a valid looking request with all required headers and a chunked body. I wonder if the chunked transfer encoding might be borked, either on the client or server side.

@eswinfen I don’t think the bodyToIterable() method is the problem. It returns a generator that you can use like this:

foreach ($body->bodyToIterable() as $value) {
    print($value);
}

I replicated the Mailgun API request by copying the headers and body created by MailgunApiTransport to Insonmia and the request was successful. So the issue seems to be somewhere in the networking layer.

I’m using PHP 8.3.4 btw.