Skip to content

Commit

Permalink
Adding configuration options to CakeEmail to set the header encoding …
Browse files Browse the repository at this point in the history
…and body encoding, also translating

all string from the App.encoding value to the configured charset if they differ. This makes possible to
send correctly emails in japanese charset
  • Loading branch information
lorenzo committed Oct 16, 2011
1 parent 3ed712e commit b38c0e5
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 15 deletions.
15 changes: 12 additions & 3 deletions app/Config/email.php.default
Expand Up @@ -30,6 +30,7 @@
* transport => The name of a supported transport; valid options are as follows:
* Mail - Send using PHP mail function
* Smtp - Send using SMTP
* Debug - Do not send the email, just return the result
*
* You can add custom transports (or override existing transports) by adding the
* appropriate file to app/Network/Email. Transports should be named 'YourTransport.php',
Expand All @@ -43,7 +44,9 @@ class EmailConfig {

public $default = array(
'transport' => 'Mail',
'from' => 'you@localhost'
'from' => 'you@localhost',
//'charset' => 'utf-8',
//'headerCharset' => 'utf-8',
);

public $smtp = array(
Expand All @@ -54,7 +57,10 @@ class EmailConfig {
'timeout' => 30,
'username' => 'user',
'password' => 'secret',
'client' => null
'client' => null,
'log' => false
//'charset' => 'utf-8',
//'headerCharset' => 'utf-8',
);

public $fast = array(
Expand Down Expand Up @@ -82,7 +88,10 @@ class EmailConfig {
'timeout' => 30,
'username' => 'user',
'password' => 'secret',
'client' => null
'client' => null,
'log' => true,
//'charset' => 'utf-8',
//'headerCharset' => 'utf-8',
);

}
15 changes: 12 additions & 3 deletions lib/Cake/Console/Templates/skel/Config/email.php.default
Expand Up @@ -30,6 +30,7 @@
* transport => The name of a supported transport; valid options are as follows:
* Mail - Send using PHP mail function
* Smtp - Send using SMTP
* Debug - Do not send the email, just return the result
*
* You can add custom transports (or override existing transports) by adding the
* appropriate file to app/Network/Email. Transports should be named 'YourTransport.php',
Expand All @@ -43,7 +44,9 @@ class EmailConfig {

public $default = array(
'transport' => 'Mail',
'from' => 'you@localhost'
'from' => 'you@localhost',
//'charset' => 'utf-8',
//'headerCharset' => 'utf-8',
);

public $smtp = array(
Expand All @@ -54,7 +57,10 @@ class EmailConfig {
'timeout' => 30,
'username' => 'user',
'password' => 'secret',
'client' => null
'client' => null,
'log' => false
//'charset' => 'utf-8',
//'headerCharset' => 'utf-8',
);

public $fast = array(
Expand Down Expand Up @@ -82,7 +88,10 @@ class EmailConfig {
'timeout' => 30,
'username' => 'user',
'password' => 'secret',
'client' => null
'client' => null,
'log' => true,
//'charset' => 'utf-8',
//'headerCharset' => 'utf-8',
);

}
60 changes: 51 additions & 9 deletions lib/Cake/Network/Email/CakeEmail.php
Expand Up @@ -239,12 +239,26 @@ class CakeEmail {
protected $_transportClass = null;

/**
* charset the email is sent in
* Charset the email body is sent in
*
*
* @var string
*/
public $charset = 'utf-8';

/**
* Charset the email header is sent in
* If null, the $charset property will be used as default
* @var string
*/
public $headerCharset = null;

/**
* The application wide charset, used to encode headers and body
* @var string
*/
public $_appCharset = null;

/**
* List of files that should be attached to the email.
*
Expand Down Expand Up @@ -274,13 +288,16 @@ class CakeEmail {
*
*/
public function __construct($config = null) {
$charset = Configure::read('App.encoding');
if ($charset !== null) {
$this->charset = $charset;
$this->_appCharset = Configure::read('App.encoding');
if ($this->_appCharset !== null) {
$this->charset = $this->_appCharset;
}
if ($config) {
$this->config($config);
}
if (empty($this->headerCharset)) {
$this->headerCharset = $this->charset;
}
}

/**
Expand Down Expand Up @@ -994,15 +1011,24 @@ public static function deliver($to = null, $subject = null, $message = null, $tr
protected function _applyConfig($config) {
if (is_string($config)) {
if (!class_exists('EmailConfig') && !config('email')) {
throw new SocketException(__d('cake_dev', '%s not found.', APP . 'Config' . DS . 'email.php'));
throw new ConfigureException(__d('cake_dev', '%s not found.', APP . 'Config' . DS . 'email.php'));
}
$configs = new EmailConfig();
if (!isset($configs->{$config})) {
throw new SocketException(__d('cake_dev', 'Unknown email configuration "%s".', $config));
throw new ConfigureException(__d('cake_dev', 'Unknown email configuration "%s".', $config));
}
$config = $configs->{$config};
}
$this->_config += $config;
if (!empty($config['charset'])) {
$this->charset = $config['charset'];
}
if (!empty($config['headerCharset'])) {
$this->headerCharset = $config['headerCharset'];
}
if (empty($this->headerCharset)) {
$this->headerCharset = $this->charset;
}
$simpleMethods = array(
'from', 'sender', 'to', 'replyTo', 'readReceipt', 'returnPath', 'cc', 'bcc',
'messageId', 'subject', 'viewRender', 'viewVars', 'attachments',
Expand Down Expand Up @@ -1073,15 +1099,31 @@ protected function _encode($text) {
$internalEncoding = function_exists('mb_internal_encoding');
if ($internalEncoding) {
$restore = mb_internal_encoding();
mb_internal_encoding($this->charset);
mb_internal_encoding($this->_appCharset);
}
$return = mb_encode_mimeheader($text, $this->charset, 'B');
$text = $this->_encodeString($text, $this->headerCharset);
$return = mb_encode_mimeheader($text, $this->headerCharset, 'B');
if ($internalEncoding) {
mb_internal_encoding($restore);
}
return $return;
}

/**
* Translates a string for one charset to another if the App.encoding value
* differs and the mb_convert_encoding function exists
*
* @param string $text The text to be converted
* @param string $charset the target encoding
* @return string
*/
protected function _encodeString($text, $charset) {
if ($this->_appCharset === $charset || !function_exists('mb_convert_encoding')) {
return $text;
}
return mb_convert_encoding($text, $charset, $this->_appCharset);
}

/**
* Wrap the message to follow the RFC 2822 - 2.1.1
*
Expand Down Expand Up @@ -1322,7 +1364,7 @@ protected function _render($content) {

$View->viewPath = $View->layoutPath = 'Emails' . DS . $this->_emailFormat;
$View->viewVars['content'] = $content;
$rendered = $View->render($template, $layout);
$rendered = $this->_encodeString($View->render($template, $layout), $this->charset);
$content = explode("\n", $rendered);

if ($this->_emailFormat === 'html') {
Expand Down
63 changes: 63 additions & 0 deletions lib/Cake/Test/Case/Network/Email/CakeEmailTest.php
Expand Up @@ -1120,4 +1120,67 @@ public function testEmailFormat() {
$result = $this->CakeEmail->emailFormat('invalid');
}

/**
* Tests that it is possible to add charset configuration to a CakeEmail object
*
* @return void
*/
public function testConfigCharset() {
$email = new CakeEmail();
$this->assertEquals($email->charset, Configure::read('App.encoding'));
$this->assertEquals($email->headerCharset, Configure::read('App.encoding'));

$email = new CakeEmail(array('charset' => 'iso-2022-jp', 'headerCharset' => 'iso-2022-jp-ms'));
$this->assertEquals($email->charset, 'iso-2022-jp');
$this->assertEquals($email->headerCharset, 'iso-2022-jp-ms');

$email = new CakeEmail(array('charset' => 'iso-2022-jp'));
$this->assertEquals($email->charset, 'iso-2022-jp');
$this->assertEquals($email->headerCharset, 'iso-2022-jp');

$email = new CakeEmail(array('headerCharset' => 'iso-2022-jp-ms'));
$this->assertEquals($email->charset, Configure::read('App.encoding'));
$this->assertEquals($email->headerCharset, 'iso-2022-jp-ms');
}

/**
* Tests that the header is encoded using the configured headerCharset
*
* @return void
*/
public function testHeaderEncoding() {
$this->skipIf(!function_exists('mb_convert_encoding'));
$email = new CakeEmail(array('headerCharset' => 'iso-2022-jp-ms', 'transport' => 'Debug'));
$email->subject('あれ?もしかしての前と');
$headers = $email->getHeaders(array('subject'));
$expected = "?ISO-2022-JP?B?GyRCJCIkbCEpJGIkNyQrJDckRiROQTAkSBsoQg==?=";
$this->assertContains($expected, $headers['Subject']);

$email->to('someone@example.com')->from('someone@example.com');
$result = $email->send('ってテーブルを作ってやってたらう');
$this->assertContains('ってテーブルを作ってやってたらう', $result['message']);
}

/**
* Tests that the body is encoded using the configured charset
*
* @return void
*/
public function testBodyEncoding() {
$this->skipIf(!function_exists('mb_convert_encoding'));
$email = new CakeEmail(array(
'charset' => 'iso-2022-jp',
'headerCharset' => 'iso-2022-jp-ms',
'transport' => 'Debug'
));
$email->subject('あれ?もしかしての前と');
$headers = $email->getHeaders(array('subject'));
$expected = "?ISO-2022-JP?B?GyRCJCIkbCEpJGIkNyQrJDckRiROQTAkSBsoQg==?=";
$this->assertContains($expected, $headers['Subject']);

$email->to('someone@example.com')->from('someone@example.com');
$result = $email->send('ってテーブルを作ってやってたらう');
$this->assertContains('Content-Type: text/plain; charset=iso-2022-jp', $result['headers']);
$this->assertContains('ってテーブルを作ってやってたらう', $result['message']);
}
}

0 comments on commit b38c0e5

Please sign in to comment.