Skip to content

Commit

Permalink
Add method to Message for getting headers as string.
Browse files Browse the repository at this point in the history
  • Loading branch information
ADmad committed Aug 24, 2019
1 parent aeac7a4 commit ce8c7e8
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 48 deletions.
31 changes: 4 additions & 27 deletions src/Mailer/AbstractTransport.php
Expand Up @@ -64,33 +64,10 @@ protected function checkRecipient(Message $message): void
&& $message->getCc() === []
&& $message->getBcc() === []
) {
throw new Exception('You must specify at least one recipient. Use one of `setTo`, `setCc` or `setBcc` to define a recipient.');
throw new Exception(
'You must specify at least one recipient.'
. ' Use one of `setTo`, `setCc` or `setBcc` to define a recipient.'
);
}
}

/**
* Help to convert headers in string
*
* @param array $headers Headers in format key => value
* @param string $eol End of line string.
* @return string
*/
protected function _headersToString(array $headers, string $eol = "\r\n"): string
{
$out = '';
foreach ($headers as $key => $value) {
if ($value === false || $value === null || $value === '') {
continue;
}

foreach ((array)$value as $val) {
$out .= $key . ': ' . $val . $eol;
}
}
if (!empty($out)) {
$out = substr($out, 0, -1 * strlen($eol));
}

return $out;
}
}
39 changes: 37 additions & 2 deletions src/Mailer/Message.php
Expand Up @@ -22,6 +22,7 @@
use Cake\Utility\Hash;
use Cake\Utility\Security;
use Cake\Utility\Text;
use Closure;
use InvalidArgumentException;
use JsonSerializable;
use Serializable;
Expand Down Expand Up @@ -854,8 +855,8 @@ public function addHeaders(array $headers)
* - `bcc`
* - `subject`
*
* @param array $include List of headers.
* @return array
* @param string[] $include List of headers.
* @return string[]
*/
public function getHeaders(array $include = []): array
{
Expand Down Expand Up @@ -934,6 +935,40 @@ public function getHeaders(array $include = []): array
return $headers;
}

/**
* Get headers as string.
*
* @param string[] $include List of headers.
* @param \Closure $callback Callback to run each header value through before stringifying.
* @param string $eol End of line string.
* @return string
* @see Message::getHeaders()
*/
public function getHeadersString(array $include = [], ?Closure $callback = null, string $eol = "\r\n"): string
{
$headers = $this->getHeaders($include);

if ($callback) {
$headers = array_map($callback, $headers);
}

$out = '';
foreach ($headers as $key => $value) {
if (empty($value) && $value !== '0') {
continue;
}

foreach ((array)$value as $val) {
$out .= $key . ': ' . $val . $eol;
}
}
if (!empty($out)) {
$out = substr($out, 0, -1 * strlen($eol));
}

return $out;
}

/**
* Format addresses
*
Expand Down
3 changes: 1 addition & 2 deletions src/Mailer/Transport/DebugTransport.php
Expand Up @@ -32,10 +32,9 @@ class DebugTransport extends AbstractTransport
*/
public function send(Message $message): array
{
$headers = $message->getHeaders(
$headers = $message->getHeadersString(
['from', 'sender', 'replyTo', 'readReceipt', 'returnPath', 'to', 'cc', 'subject']
);
$headers = $this->_headersToString($headers);
$message = implode("\r\n", (array)$message->getBody());

return ['headers' => $headers, 'message' => $message];
Expand Down
33 changes: 17 additions & 16 deletions src/Mailer/Transport/MailTransport.php
Expand Up @@ -38,22 +38,23 @@ public function send(Message $message): array
if (isset($this->_config['eol'])) {
$eol = $this->_config['eol'];
}
$headers = $message->getHeaders([
'from',
'sender',
'replyTo',
'readReceipt',
'returnPath',
'to',
'cc',
'bcc',
]);
$to = $headers['To'];
unset($headers['To']);
foreach ($headers as $key => $header) {
$headers[$key] = str_replace(["\r", "\n"], '', $header);
}
$headers = $this->_headersToString($headers, $eol);
$to = $message->getHeaders(['to'])['To'];
$headers = $message->getHeadersString(
[
'from',
'sender',
'replyTo',
'readReceipt',
'returnPath',
'cc',
'bcc',
],
function ($val) {
return str_replace(["\r", "\n"], '', $val);
},
$eol
);

$subject = str_replace(["\r", "\n"], '', $message->getSubject());
$to = str_replace(["\r", "\n"], '', $to);

Expand Down
11 changes: 10 additions & 1 deletion src/Mailer/Transport/SmtpTransport.php
Expand Up @@ -408,7 +408,16 @@ protected function _sendData(Message $message): void
{
$this->_smtpSend('DATA', '354');

$headers = $this->_headersToString($this->_prepareMessageHeaders($message));
$headers = $message->getHeadersString([
'from',
'sender',
'replyTo',
'readReceipt',
'to',
'cc',
'subject',
'returnPath'
]);
$message = $this->_prepareMessage($message);

$this->_smtpSend($headers . "\r\n\r\n" . $message . "\r\n\r\n\r\n.");
Expand Down
113 changes: 113 additions & 0 deletions tests/TestCase/Mailer/MessageTest.php
Expand Up @@ -25,6 +25,18 @@
*/
class MessageTest extends TestCase
{
/**
* @var \Cake\Mailer\Message
*/
protected $message;

public function setUp(): void
{
parent::setUp();

$this->message = new Message();
}

/**
* testWrap method
*
Expand Down Expand Up @@ -93,4 +105,105 @@ public function testWrap()
];
$this->assertSame($expected, $result);
}

/**
* testHeaders method
*
* @return void
*/
public function testHeaders()
{
$this->message->setMessageId(false);
$this->message->setHeaders(['X-Something' => 'nice']);
$expected = [
'X-Something' => 'nice',
'Date' => date(DATE_RFC2822),
'MIME-Version' => '1.0',
'Content-Type' => 'text/plain; charset=UTF-8',
'Content-Transfer-Encoding' => '8bit',
];
$this->assertSame($expected, $this->message->getHeaders());

$this->message->addHeaders(['X-Something' => 'very nice', 'X-Other' => 'cool']);
$expected = [
'X-Something' => 'very nice',
'X-Other' => 'cool',
'Date' => date(DATE_RFC2822),
'MIME-Version' => '1.0',
'Content-Type' => 'text/plain; charset=UTF-8',
'Content-Transfer-Encoding' => '8bit',
];
$this->assertSame($expected, $this->message->getHeaders());

$this->message->setFrom('cake@cakephp.org');
$this->assertSame($expected, $this->message->getHeaders());

$expected = [
'From' => 'cake@cakephp.org',
'X-Something' => 'very nice',
'X-Other' => 'cool',
'Date' => date(DATE_RFC2822),
'MIME-Version' => '1.0',
'Content-Type' => 'text/plain; charset=UTF-8',
'Content-Transfer-Encoding' => '8bit',
];
$this->assertSame($expected, $this->message->getHeaders(['from' => true]));

$this->message->setFrom('cake@cakephp.org', 'CakePHP');
$expected['From'] = 'CakePHP <cake@cakephp.org>';
$this->assertSame($expected, $this->message->getHeaders(['from' => true]));

$this->message->setTo(['cake@cakephp.org', 'php@cakephp.org' => 'CakePHP']);
$expected = [
'From' => 'CakePHP <cake@cakephp.org>',
'To' => 'cake@cakephp.org, CakePHP <php@cakephp.org>',
'X-Something' => 'very nice',
'X-Other' => 'cool',
'Date' => date(DATE_RFC2822),
'MIME-Version' => '1.0',
'Content-Type' => 'text/plain; charset=UTF-8',
'Content-Transfer-Encoding' => '8bit',
];
$this->assertSame($expected, $this->message->getHeaders(['from' => true, 'to' => true]));

$this->message->setCharset('ISO-2022-JP');
$expected = [
'From' => 'CakePHP <cake@cakephp.org>',
'To' => 'cake@cakephp.org, CakePHP <php@cakephp.org>',
'X-Something' => 'very nice',
'X-Other' => 'cool',
'Date' => date(DATE_RFC2822),
'MIME-Version' => '1.0',
'Content-Type' => 'text/plain; charset=ISO-2022-JP',
'Content-Transfer-Encoding' => '7bit',
];
$this->assertSame($expected, $this->message->getHeaders(['from' => true, 'to' => true]));

$result = $this->message->setHeaders([]);
$this->assertInstanceOf(Message::class, $result);

$this->message->setHeaders(['o:tag' => ['foo']]);
$this->message->addHeaders(['o:tag' => ['bar']]);
$result = $this->message->getHeaders();
$this->assertEquals(['foo', 'bar'], $result['o:tag']);
}

/**
* testHeadersString method
*
* @return void
*/
public function testHeadersString()
{
$this->message->setMessageId(false);
$this->message->setHeaders(['X-Something' => 'nice']);
$expected = [
'X-Something: nice',
'Date: ' . date(DATE_RFC2822),
'MIME-Version: 1.0',
'Content-Type: text/plain; charset=UTF-8',
'Content-Transfer-Encoding: 8bit',
];
$this->assertSame(implode("\r\n", $expected), $this->message->getHeadersString());
}
}

0 comments on commit ce8c7e8

Please sign in to comment.