Merge pull request #460 from kijin/pr/advanced-mailer

고급 메일 발송 모듈의 기능을 라이믹스에 포함
This commit is contained in:
Kijin Sung 2016-05-23 22:03:37 +09:00
commit 9a7445b677
141 changed files with 5770 additions and 683 deletions

View file

@ -1,36 +1,12 @@
<?php
/**
* Mail class
* Mail class for XE Compatibility
*
* @author Kijin Sung <kijin@kijinsung.com>
*/
class Mail
class Mail extends Rhymix\Framework\Mail
{
/**
* Properties for compatibility with XE Mail class
*/
public $content = '';
public $content_type = 'html';
public $attachments = array();
public $cidAttachments = array();
/**
* Properties used by Advanced Mailer
*/
public $error = null;
public $caller = null;
public $message = null;
public static $transport = null;
/**
* Constructor
*/
public function __construct()
{
$this->message = \Swift_Message::newInstance();
}
/**
* Set parameters for using Gmail
*
@ -57,14 +33,13 @@ class Mail
*/
public static function useSMTP($auth = null, $host = null, $user = null, $pass = null, $secure = null, $port = 25)
{
self::$transport = \Swift_SmtpTransport::newInstance($host, $port, $secure);
self::$transport->setUsername($user);
self::$transport->setPassword($pass);
$local_domain = self::$transport->getLocalDomain();
if (preg_match('/^\*\.(.+)$/', $local_domain, $matches))
{
self::$transport->setLocalDomain($matches[1]);
}
self::setDefaultDriver(Rhymix\Framework\Drivers\Mail\SMTP::getInstance(array(
'smtp_host' => $host,
'smtp_port' => $port,
'smtp_security' => $secure,
'smtp_user' => $user,
'smtp_pass' => $pass,
)));
}
/**
@ -76,7 +51,7 @@ class Mail
}
/**
* Set Sender (From:)
* Set the sender (From:).
*
* @param string $name Sender name
* @param string $email Sender email address
@ -84,36 +59,17 @@ class Mail
*/
public function setSender($name, $email)
{
try
{
$this->message->setFrom(array($email => $name));
}
catch (\Exception $e)
{
$this->errors[] = array($e->getMessage());
}
$this->setFrom($email, $name ?: null);
}
/**
* Get Sender (From:)
* Get the sender.
*
* @return string
*/
public function getSender()
{
$from = $this->message->getFrom();
foreach($from as $email => $name)
{
if($name === '')
{
return $email;
}
else
{
return $name . ' <' . $email . '>';
}
}
return FALSE;
return $this->getFrom() ?: false;
}
/**
@ -125,14 +81,8 @@ class Mail
*/
public function setReceiptor($name, $email)
{
try
{
$this->message->setTo(array($email => $name));
}
catch (\Exception $e)
{
$this->errors[] = array($e->getMessage());
}
$this->message->setTo(array());
return $this->addTo($email, $name ?: null);
}
/**
@ -142,40 +92,8 @@ class Mail
*/
public function getReceiptor()
{
$to = $this->message->getTo();
foreach($to as $email => $name)
{
if($name === '')
{
return $email;
}
else
{
return $name . ' <' . $email . '>';
}
}
return FALSE;
}
/**
* Set Subject
*
* @param string $subject The subject
* @return void
*/
public function setTitle($subject)
{
$this->message->setSubject(strval($subject));
}
/**
* Get Subject
*
* @return string
*/
public function getTitle()
{
return $this->message->getSubject();
$list = $this->getRecipients();
return $list ? array_first($list) : false;
}
/**
@ -186,96 +104,8 @@ class Mail
*/
public function setBCC($bcc)
{
try
{
$this->message->setBcc(array($bcc));
}
catch (\Exception $e)
{
$this->errors[] = array($e->getMessage());
}
}
/**
* Set ReplyTo
*
* @param string $replyTo
* @return void
*/
public function setReplyTo($replyTo)
{
try
{
$this->message->setReplyTo(array($replyTo));
}
catch (\Exception $e)
{
$this->errors[] = array($e->getMessage());
}
}
/**
* Set Return Path
*
* @param string $returnPath
* @return void
*/
public function setReturnPath($returnPath)
{
try
{
$this->message->setReturnPath($returnPath);
}
catch (\Exception $e)
{
$this->errors[] = array($e->getMessage());
}
}
/**
* Set Message ID
*
* @param string $messageId
* @return void
*/
public function setMessageID($messageId)
{
$this->message->getHeaders()->get('Message-ID')->setId($messageId);
}
/**
* Set references
*
* @param string $references
* @return void
*/
public function setReferences($references)
{
$headers = $this->message->getHeaders();
$headers->addTextHeader('References', $references);
}
/**
* Set message content
*
* @param string $content Content
* @return void
*/
public function setContent($content)
{
$content = preg_replace_callback('/<img([^>]+)>/i', array($this, 'replaceResourceRealPath'), $content);
$this->content = $content;
}
/**
* Set the type of message content (html or plain text)
*
* @param string $mode The type
* @return void
*/
public function setContentType($type = 'html')
{
$this->content_type = $type === 'html' ? 'html' : '';
$this->message->setBcc(array());
return $this->addBcc($bcc);
}
/**
@ -285,7 +115,7 @@ class Mail
*/
public function getPlainContent()
{
return chunk_split(base64_encode(str_replace(array("<", ">", "&"), array("&lt;", "&gt;", "&amp;"), $this->content)));
return chunk_split(base64_encode(htmlspecialchars($this->message->getBody())));
}
/**
@ -295,19 +125,19 @@ class Mail
*/
public function getHTMLContent()
{
return chunk_split(base64_encode($this->content_type != 'html' ? nl2br($this->content) : $this->content));
return chunk_split(base64_encode($this->content_type != 'text/html' ? nl2br($this->message->getBody()) : $this->message->getBody()));
}
/**
* Add file attachment
*
* @param string $filename File name to attach
* @param string $original_filename Real path of file to attach
* @param string $filename File name to attach
* @return void
*/
public function addAttachment($filename, $original_filename)
public function addAttachment($original_filename, $filename)
{
$this->attachments[$original_filename] = $filename;
return $this->attach($original_filename, $filename);
}
/**
@ -317,21 +147,9 @@ class Mail
* @param string $cid Content-CID
* @return void
*/
public function addCidAttachment($original_filename, $cid)
public function addCidAttachment($original_filename, $cid = null)
{
$this->cidAttachments[$cid] = $original_filename;
}
/**
* Replace resourse path of the files
*
* @see Mail::setContent()
* @param array $matches Match info.
* @return string
*/
public function replaceResourceRealPath($matches)
{
return preg_replace('/src=(["\']?)files/i', 'src=$1' . \Context::getRequestUri() . 'files', $matches[0]);
return $this->embed($original_filename, $cid);
}
/**
@ -354,66 +172,13 @@ class Mail
// no-op
}
/**
* Process the message before sending
*
* @return void
*/
public function procAssembleMessage()
{
// Add all attachments
foreach($this->attachments as $original_filename => $filename)
{
$attachment = \Swift_Attachment::fromPath($original_filename);
$attachment->setFilename($filename);
$this->message->attach($attachment);
}
// Add all CID attachments
foreach($this->cidAttachments as $cid => $original_filename)
{
$embedded = \Swift_EmbeddedFile::fromPath($original_filename);
$newcid = $this->message->embed($embedded);
$this->content = str_replace(array("cid:$cid", $cid), $newcid, $this->content);
}
// Set content type
$content_type = $this->content_type === 'html' ? 'text/html' : 'text/plain';
$this->message->setBody($this->content, $content_type);
}
/**
* Send email
*
* @return bool
*/
public function send()
{
try
{
$this->procAssembleMessage();
if(!self::$transport)
{
self::$transport = \Swift_MailTransport::newInstance();
}
$mailer = \Swift_Mailer::newInstance(self::$transport);
$result = $mailer->send($this->message, $this->errors);
return (bool)$result;
}
catch(\Exception $e)
{
$this->error = $e->getMessage();
return false;
}
}
/**
* Check if DNS of param is real or fake
*
* @param string $email_address Email address to check
* @return bool
*/
public function checkMailMX($email_address)
public static function checkMailMX($email_address)
{
if(!self::isVaildMailAddress($email_address))
{
@ -434,13 +199,23 @@ class Mail
return TRUE;
}
/**
* Check if this class supports Advanced Mailer features.
*
* @return bool
*/
public static function isAdvancedMailer()
{
return true;
}
/**
* Check if param is a valid email or not
*
* @param string $email_address Email address to check
* @return string
*/
public function isVaildMailAddress($email_address)
public static function isVaildMailAddress($email_address)
{
if(preg_match("/([a-z0-9\_\-\.]+)@([a-z0-9\_\-\.]+)/i", $email_address))
{
@ -458,7 +233,7 @@ class Mail
* @param string $filename filename
* @return string MIME type of ext
*/
function returnMIMEType($filename)
public static function returnMIMEType($filename)
{
return Rhymix\Framework\MIME::getTypeByFilename($filename);
}

View file

@ -60,16 +60,7 @@ return array(
'umask' => '022',
),
'mail' => array(
'transport' => 'mail',
'smtp_host' => null,
'smtp_port' => null,
'smtp_security' => 'none',
'smtp_user' => null,
'smtp_pass' => null,
'api_domain' => null,
'api_token' => null,
'api_user' => null,
'api_pass' => null,
'type' => 'mailfunction',
),
'view' => array(
'minify_scripts' => 'common',

View file

@ -0,0 +1,113 @@
<?php
namespace Rhymix\Framework\Drivers\Mail;
/**
* The base class for other mail drivers.
*/
abstract class Base implements \Rhymix\Framework\Drivers\MailInterface
{
/**
* The configuration is stored here.
*/
protected $_config = null;
/**
* The mailer instance is stored here.
*/
protected $_mailer = null;
/**
* Direct invocation of the constructor is not permitted.
*/
protected function __construct(array $config)
{
$this->_config = $config;
}
/**
* Create a new instance of the current mail driver, using the given settings.
*
* @param array $config
* @return void
*/
public static function getInstance(array $config)
{
return new static($config);
}
/**
* Get the human-readable name of this mail driver.
*
* @return string
*/
public static function getName()
{
return class_basename(get_called_class());
}
/**
* Get the list of configuration fields required by this mail driver.
*
* @return array
*/
public static function getRequiredConfig()
{
return array();
}
/**
* Get the list of API types supported by this mail driver.
*
* @return array
*/
public static function getAPITypes()
{
return array();
}
/**
* Get the SPF hint.
*
* @return string
*/
public static function getSPFHint()
{
return '';
}
/**
* Get the DKIM hint.
*
* @return string
*/
public static function getDKIMHint()
{
return '';
}
/**
* Check if the current mail driver is supported on this server.
*
* This method returns true on success and false on failure.
*
* @return bool
*/
public static function isSupported()
{
return false;
}
/**
* Send a message.
*
* This method returns true on success and false on failure.
*
* @param object $message
* @return bool
*/
public function send(\Rhymix\Framework\Mail $message)
{
return false;
}
}

View file

@ -0,0 +1,34 @@
<?php
namespace Rhymix\Framework\Drivers\Mail;
/**
* The dummy mail driver.
*/
class Dummy extends Base implements \Rhymix\Framework\Drivers\MailInterface
{
/**
* Check if the current mail driver is supported on this server.
*
* This method returns true on success and false on failure.
*
* @return bool
*/
public static function isSupported()
{
return true;
}
/**
* Send a message.
*
* This method returns true on success and false on failure.
*
* @param object $message
* @return bool
*/
public function send(\Rhymix\Framework\Mail $message)
{
return true;
}
}

View file

@ -0,0 +1,76 @@
<?php
namespace Rhymix\Framework\Drivers\Mail;
/**
* The mail() function mail driver.
*/
class MailFunction extends Base implements \Rhymix\Framework\Drivers\MailInterface
{
/**
* Direct invocation of the constructor is not permitted.
*/
protected function __construct()
{
$this->mailer = \Swift_Mailer::newInstance(\Swift_MailTransport::newInstance());
}
/**
* Get the human-readable name of this mail driver.
*
* @return string
*/
public static function getName()
{
return 'PHP mail()';
}
/**
* Get the SPF hint.
*
* @return string
*/
public static function getSPFHint()
{
return 'ip4:$SERVER_ADDR';
}
/**
* Check if the current mail driver is supported on this server.
*
* This method returns true on success and false on failure.
*
* @return bool
*/
public static function isSupported()
{
return true;
}
/**
* Send a message.
*
* This method returns true on success and false on failure.
*
* @param object $message
* @return bool
*/
public function send(\Rhymix\Framework\Mail $message)
{
try
{
$result = $this->mailer->send($message->message, $errors);
}
catch(\Exception $e)
{
$message->errors[] = $e->getMessage();
return false;
}
foreach ($errors as $error)
{
$message->errors[] = $error;
}
return (bool)$result;
}
}

View file

@ -0,0 +1,137 @@
<?php
namespace Rhymix\Framework\Drivers\Mail;
/**
* The Mailgun mail driver.
*/
class Mailgun extends Base implements \Rhymix\Framework\Drivers\MailInterface
{
/**
* The API URL.
*/
protected static $_url = 'https://api.mailgun.net/v3';
/**
* Get the list of configuration fields required by this mail driver.
*
* @return array
*/
public static function getRequiredConfig()
{
return array('api_domain', 'api_token');
}
/**
* Get the SPF hint.
*
* @return string
*/
public static function getSPFHint()
{
return 'include:mailgun.org';
}
/**
* Get the DKIM hint.
*
* @return string
*/
public static function getDKIMHint()
{
return 'mailo._domainkey';
}
/**
* Check if the current mail driver is supported on this server.
*
* This method returns true on success and false on failure.
*
* @return bool
*/
public static function isSupported()
{
return true;
}
/**
* Send a message.
*
* This method returns true on success and false on failure.
*
* @param object $message
* @return bool
*/
public function send(\Rhymix\Framework\Mail $message)
{
// Assemble the list of recipients.
$recipients = array();
if ($to = $message->message->getTo())
{
foreach($to as $address => $name)
{
$recipients[] = $address;
}
}
if ($cc = $message->message->getCc())
{
foreach($cc as $address => $name)
{
$recipients[] = $address;
}
}
if ($bcc = $message->message->getBcc())
{
foreach($bcc as $address => $name)
{
$recipients[] = $address;
}
}
// Prepare data and options for Requests.
$boundary = str_repeat('-', 24) . substr(md5(mt_rand()), 0, 16);
$headers = array(
'Content-Type' => 'multipart/form-data; boundary=' . $boundary,
);
$data = implode("\r\n", array(
'--' . $boundary,
'Content-Disposition: form-data; name="to"',
'',
implode(', ', $recipients),
'--' . $boundary,
'Content-Disposition: attachment; name="message"; filename="message.eml"',
'Content-Type: message/rfc822',
'Content-Transfer-Encoding: binary',
'',
$message->message->toString(),
'--' . $boundary . '--',
'',
));
$options = array(
'auth' => array('api', $this->_config['api_token']),
'timeout' => 5,
'useragent' => 'PHP',
);
// Send the API request.
$url = self::$_url . '/' . $this->_config['api_domain'] . '/messages.mime';
$request = \Requests::post($url, $headers, $data, $options);
$result = @json_decode($request->body);
// Parse the result.
if (!$result)
{
$message->errors[] = 'Mailgun: Connection error: ' . $request->body;
return false;
}
elseif (!$result->id)
{
$message->errors[] = 'Mailgun: ' . $result->message;
return false;
}
else
{
return true;
}
}
}

View file

@ -0,0 +1,52 @@
<?php
namespace Rhymix\Framework\Drivers\Mail;
/**
* The Mandrill mail driver.
*/
class Mandrill extends SMTP implements \Rhymix\Framework\Drivers\MailInterface
{
/**
* Direct invocation of the constructor is not permitted.
*/
protected function __construct(array $config)
{
$config['smtp_host'] = 'smtp.mandrillapp.com';
$config['smtp_port'] = 465;
$config['smtp_security'] = 'ssl';
$config['smtp_user'] = $config['api_user'];
$config['smtp_pass'] = $config['api_token'];
parent::__construct($config);
}
/**
* Get the list of configuration fields required by this mail driver.
*
* @return array
*/
public static function getRequiredConfig()
{
return array('api_user', 'api_token');
}
/**
* Get the SPF hint.
*
* @return string
*/
public static function getSPFHint()
{
return 'include:spf.mandrillapp.com';
}
/**
* Get the DKIM hint.
*
* @return string
*/
public static function getDKIMHint()
{
return 'mandrill._domainkey';
}
}

View file

@ -0,0 +1,52 @@
<?php
namespace Rhymix\Framework\Drivers\Mail;
/**
* The Postmark mail driver.
*/
class Postmark extends SMTP implements \Rhymix\Framework\Drivers\MailInterface
{
/**
* Direct invocation of the constructor is not permitted.
*/
protected function __construct(array $config)
{
$config['smtp_host'] = 'smtp.postmarkapp.com';
$config['smtp_port'] = 587;
$config['smtp_security'] = 'tls';
$config['smtp_user'] = $config['api_token'];
$config['smtp_pass'] = $config['api_token'];
parent::__construct($config);
}
/**
* Get the list of configuration fields required by this mail driver.
*
* @return array
*/
public static function getRequiredConfig()
{
return array('api_token');
}
/**
* Get the SPF hint.
*
* @return string
*/
public static function getSPFHint()
{
return 'include:spf.mtasv.net';
}
/**
* Get the DKIM hint.
*
* @return string
*/
public static function getDKIMHint()
{
return '********.pm._domainkey';
}
}

View file

@ -0,0 +1,52 @@
<?php
namespace Rhymix\Framework\Drivers\Mail;
/**
* The SendGrid mail driver.
*/
class SendGrid extends SMTP implements \Rhymix\Framework\Drivers\MailInterface
{
/**
* Direct invocation of the constructor is not permitted.
*/
protected function __construct(array $config)
{
$config['smtp_host'] = 'smtp.sendgrid.net';
$config['smtp_port'] = 465;
$config['smtp_security'] = 'ssl';
$config['smtp_user'] = $config['api_user'];
$config['smtp_pass'] = $config['api_pass'];
parent::__construct($config);
}
/**
* Get the list of configuration fields required by this mail driver.
*
* @return array
*/
public static function getRequiredConfig()
{
return array('api_user', 'api_pass');
}
/**
* Get the SPF hint.
*
* @return string
*/
public static function getSPFHint()
{
return 'include:sendgrid.net';
}
/**
* Get the DKIM hint.
*
* @return string
*/
public static function getDKIMHint()
{
return 'smtpapi._domainkey';
}
}

View file

@ -0,0 +1,120 @@
<?php
namespace Rhymix\Framework\Drivers\Mail;
/**
* The Amazon SES mail driver.
*/
class SES extends Base implements \Rhymix\Framework\Drivers\MailInterface
{
/**
* Cache the message here for debug access.
*/
protected $_message;
/**
* Direct invocation of the constructor is not permitted.
*/
protected function __construct(array $config)
{
$transport = \Swift_AWSTransport::newInstance($config['api_user'], $config['api_pass']);
$transport->setDebug(array($this, 'debugCallback'));
$transport->setEndpoint('https://email.' . strtolower($config['api_type']) . '.amazonaws.com/');
$this->mailer = \Swift_Mailer::newInstance($transport);
}
/**
* Get the list of configuration fields required by this mail driver.
*
* @return array
*/
public static function getRequiredConfig()
{
return array('api_user', 'api_pass', 'api_type');
}
/**
* Get the list of API types supported by this mail driver.
*
* @return array
*/
public static function getAPITypes()
{
return array('us-east-1', 'us-west-2', 'eu-west-1');
}
/**
* Get the SPF hint.
*
* @return string
*/
public static function getSPFHint()
{
return '';
}
/**
* Get the DKIM hint.
*
* @return string
*/
public static function getDKIMHint()
{
return '********._domainkey';
}
/**
* Check if the current mail driver is supported on this server.
*
* This method returns true on success and false on failure.
*
* @return bool
*/
public static function isSupported()
{
return true;
}
/**
* Send a message.
*
* This method returns true on success and false on failure.
*
* @param object $message
* @return bool
*/
public function send(\Rhymix\Framework\Mail $message)
{
$this->_message = $message;
try
{
$result = $this->mailer->send($message->message, $errors);
}
catch(\Exception $e)
{
$message->errors[] = $e->getMessage();
return false;
}
foreach ($errors as $error)
{
$message->errors[] = $error;
}
return (bool)$result;
}
/**
* Debug callback function for SES transport.
*
* @param string $msg
* @return void
*/
public function debugCallback($msg)
{
if ($this->_message)
{
$this->_message->errors[] = $msg;
}
}
}

View file

@ -0,0 +1,74 @@
<?php
namespace Rhymix\Framework\Drivers\Mail;
/**
* The SMTP mail driver.
*/
class SMTP extends Base implements \Rhymix\Framework\Drivers\MailInterface
{
/**
* Direct invocation of the constructor is not permitted.
*/
protected function __construct(array $config)
{
$transport = \Swift_SmtpTransport::newInstance($config['smtp_host'], $config['smtp_port'], $config['smtp_security']);
$transport->setUsername($config['smtp_user']);
$transport->setPassword($config['smtp_pass']);
$local_domain = $transport->getLocalDomain();
if (preg_match('/^\*\.(.+)$/', $local_domain, $matches))
{
$transport->setLocalDomain($matches[1]);
}
$this->mailer = \Swift_Mailer::newInstance($transport);
}
/**
* Get the list of configuration fields required by this mail driver.
*
* @return array
*/
public static function getRequiredConfig()
{
return array('smtp_host', 'smtp_port', 'smtp_security', 'smtp_user', 'smtp_pass');
}
/**
* Check if the current mail driver is supported on this server.
*
* This method returns true on success and false on failure.
*
* @return bool
*/
public static function isSupported()
{
return function_exists('proc_open');
}
/**
* Send a message.
*
* This method returns true on success and false on failure.
*
* @param object $message
* @return bool
*/
public function send(\Rhymix\Framework\Mail $message)
{
try
{
$result = $this->mailer->send($message->message, $errors);
}
catch(\Exception $e)
{
$message->errors[] = $e->getMessage();
return false;
}
foreach ($errors as $error)
{
$message->errors[] = 'Failed to send to ' . $error;
}
return (bool)$result;
}
}

View file

@ -0,0 +1,137 @@
<?php
namespace Rhymix\Framework\Drivers\Mail;
/**
* The SparkPost mail driver.
*/
class SparkPost extends Base implements \Rhymix\Framework\Drivers\MailInterface
{
/**
* The API URL.
*/
protected static $_url = 'https://api.sparkpost.com/api/v1/transmissions';
/**
* Get the list of configuration fields required by this mail driver.
*
* @return array
*/
public static function getRequiredConfig()
{
return array('api_token');
}
/**
* Get the SPF hint.
*
* @return string
*/
public static function getSPFHint()
{
return 'include:sparkpostmail.com';
}
/**
* Get the DKIM hint.
*
* @return string
*/
public static function getDKIMHint()
{
return '********._domainkey';
}
/**
* Check if the current mail driver is supported on this server.
*
* This method returns true on success and false on failure.
*
* @return bool
*/
public static function isSupported()
{
return true;
}
/**
* Send a message.
*
* This method returns true on success and false on failure.
*
* @param object $message
* @return bool
*/
public function send(\Rhymix\Framework\Mail $message)
{
// Assemble the list of recipients.
$recipients = array();
if ($to = $message->message->getTo())
{
foreach($to as $address => $name)
{
$recipients[] = array('address' => array('name' => $name, 'email' => $address));
}
}
if ($cc = $message->message->getCc())
{
foreach($cc as $address => $name)
{
$recipients[] = array('address' => array('name' => $name, 'email' => $address));
}
}
if ($bcc = $message->message->getBcc())
{
foreach($bcc as $address => $name)
{
$recipients[] = array('address' => array('name' => $name, 'email' => $address));
}
}
// Prepare data and options for Requests.
$headers = array(
'Authorization' => $this->_config['api_token'],
'Content-Type' => 'application/json',
);
$data = json_encode(array(
'options' => array(
'transactional' => true,
),
'recipients' => $recipients,
'content' => array(
'email_rfc822' => $message->message->toString(),
),
));
$options = array(
'timeout' => 5,
'useragent' => 'PHP',
);
// Send the API request.
$request = \Requests::post(self::$_url, $headers, $data, $options);
$result = @json_decode($request->body);
// Parse the result.
if (!$result)
{
$message->errors[] = 'SparkPost: Connection error: ' . $request->body;
return false;
}
elseif ($result->errors)
{
foreach ($result->errors as $error)
{
$message->errors[] = 'SparkPost: ' . $error->message . ': ' . $error->description . ' (code ' . $error->code . ')';
}
}
if ($result->results)
{
return $result->results->total_accepted_recipients > 0 ? true : false;
}
else
{
return false;
}
}
}

View file

@ -0,0 +1,199 @@
<?php
namespace Rhymix\Framework\Drivers\Mail;
/**
* The Woorimail mail driver.
*/
class Woorimail extends Base implements \Rhymix\Framework\Drivers\MailInterface
{
/**
* The API URL.
*/
protected static $_url = 'https://woorimail.com:20080/index.php';
/**
* Error codes and messages.
*/
protected static $_error_codes = array(
'me_001' => '@ 없는 이메일 주소가 있습니다.',
'me_002' => '이메일 주소가 존재하지 않습니다.',
'me_003' => '닉네임이 존재하지 않습니다.',
'me_004' => '등록일이 존재하지 않습니다.',
'me_005' => '이메일과 닉네임 갯수가 다릅니다.',
'me_006' => '닉네임과 등록일 갯수가 다릅니다.',
'me_007' => '이메일과 등록일 갯수가 다릅니다.',
'me_008' => '이메일 갯수가 2,000개가 넘습니다.',
'me_009' => 'type이 api가 아닙니다.',
'me_010' => '인증키가 없습니다.',
'me_011' => '인증키가 부정확합니다.',
'me_012' => '포인트가 부족합니다.',
'me_013' => '전용채널에 도메인이 등록되어 있지 않습니다.',
);
/**
* Get the list of configuration fields required by this mail driver.
*
* @return array
*/
public static function getRequiredConfig()
{
return array('api_domain', 'api_token', 'api_type');
}
/**
* Get the list of API types supported by this mail driver.
*
* @return array
*/
public static function getAPITypes()
{
return array('free', 'paid');
}
/**
* Get the SPF hint.
*
* @return string
*/
public static function getSPFHint()
{
return 'include:woorimail.com';
}
/**
* Get the DKIM hint.
*
* @return string
*/
public static function getDKIMHint()
{
return '';
}
/**
* Check if the current mail driver is supported on this server.
*
* This method returns true on success and false on failure.
*
* @return bool
*/
public static function isSupported()
{
return true;
}
/**
* Send a message.
*
* This method returns true on success and false on failure.
*
* @param object $message
* @return bool
*/
public function send(\Rhymix\Framework\Mail $message)
{
// Assemble the POST data.
$data = array(
'type' => 'api',
'mid' => 'auth_woorimail',
'act' => 'dispWwapimanagerMailApi',
'title' => $message->getSubject(),
'content' => $message->getBody(),
'sender_email' => '',
'sender_nickname' => '',
'receiver_email' => array(),
'receiver_nickname' => array(),
'member_regdate' => date('YmdHis'),
'domain' => $this->_config['api_domain'],
'authkey' => $this->_config['api_token'],
'wms_domain' => 'woorimail.com',
'wms_nick' => 'NOREPLY',
'callback' => '',
'is_sendok' => 'W',
);
// Fill the sender info.
$from = $message->message->getFrom();
foreach($from as $email => $name)
{
$data['sender_email'] = $email;
$data['sender_nickname'] = $name;
break;
}
if(isset($this->_config['api_type']) && $this->_config['api_type'] === 'paid')
{
$sender_email = explode('@', $data['sender_email']);
if(count($sender_email) === 2)
{
$data['wms_nick'] = $sender_email[0];
$data['wms_domain'] = $sender_email[1];
}
}
// Fill the recipient info.
if ($to = $message->message->getTo())
{
foreach($to as $email => $name)
{
$data['receiver_email'][] = $email;
$data['receiver_nickname'][] = str_replace(',', '', $name);
}
}
if ($cc = $message->message->getCc())
{
foreach($cc as $email => $name)
{
$data['receiver_email'][] = $email;
$data['receiver_nickname'][] = str_replace(',', '', $name);
}
}
if ($bcc = $message->message->getBcc())
{
foreach($bcc as $email => $name)
{
$data['receiver_email'][] = $email;
$data['receiver_nickname'][] = str_replace(',', '', $name);
}
}
$data['receiver_email'] = implode(',', $data['receiver_email']);
$data['receiver_nickname'] = implode(',', $data['receiver_nickname']);
// Define connection options.
$options = array(
'timeout' => 5,
'useragent' => 'PHP',
);
// Send the API request.
$request = \Requests::post(self::$_url, array(), $data, $options);
$result = @json_decode($request->body);
// Parse the result.
if (!$result)
{
$message->errors[] = 'Woorimail: Connection error: ' . $request->body;
return false;
}
elseif($result->result === 'OK')
{
return true;
}
else
{
if(isset($result->error_msg))
{
if(isset(self::$_error_codes[$result->error_msg]))
{
$result->error_msg .= ' ' . self::$_error_codes[$result->error_msg];
}
$message->errors[] = 'Woorimail: ' . $result->error_msg;
}
else
{
$message->errors[] = 'Woorimail: Connection error';
}
return false;
}
}
}

View file

@ -0,0 +1,71 @@
<?php
namespace Rhymix\Framework\Drivers;
/**
* The mail driver interface.
*/
interface MailInterface
{
/**
* Create a new instance of the current mail driver, using the given settings.
*
* @param array $config
* @return void
*/
public static function getInstance(array $config);
/**
* Get the human-readable name of this mail driver.
*
* @return string
*/
public static function getName();
/**
* Get the list of configuration fields required by this mail driver.
*
* @return array
*/
public static function getRequiredConfig();
/**
* Get the list of API types supported by this mail driver.
*
* @return array
*/
public static function getAPITypes();
/**
* Get the SPF hint.
*
* @return string
*/
public static function getSPFHint();
/**
* Get the DKIM hint.
*
* @return string
*/
public static function getDKIMHint();
/**
* Check if the current mail driver is supported on this server.
*
* This method returns true on success and false on failure.
*
* @return bool
*/
public static function isSupported();
/**
* Send a message.
*
* This method returns true on success and false on failure.
*
* @param object $message
* @return bool
*/
public function send(\Rhymix\Framework\Mail $message);
}

View file

@ -0,0 +1,101 @@
<?php
namespace Rhymix\Framework\Helpers;
use Rhymix\Framework\Config;
use Rhymix\Framework\Plugin;
/**
* Config helper class.
*/
class ConfigHelper
{
/**
* Cache plugin configuration during consolidation.
*/
protected static $_config_cache = array();
/**
* Consolidate configuration from multiple sources.
*
* @param array $format
* @return array
*/
public static function consolidate($format)
{
self::$_config_cache = array();
$result = array();
foreach ($format as $key => $value)
{
$result[$key] = self::_parseConfigValue((array)$value);
}
self::$_config_cache = array();
return $result;
}
/**
* Parse and get a configuration value.
*
* @param array $value
* @return mixed
*/
protected static function _parseConfigValue(array $value)
{
$filters = array();
$result = null;
foreach ($value as $option)
{
$option = array_map('trim', explode(':', $option, 2));
if (count($option) === 1)
{
if (function_exists($option[0]))
{
$filters[] = $option[0];
}
}
elseif ($result !== null)
{
continue;
}
elseif ($option[0] === 'common')
{
$result = Config::get($option[1]);
}
else
{
if (!isset(self::$_config_cache[$option[0]]))
{
self::$_config_cache[$option[0]] = getModel('module')->getModuleConfig($option[0]) ?: new stdClass;
}
$options = explode('.', $option[1]);
$temp = self::$_config_cache[$option[0]];
foreach ($options as $step)
{
if (is_object($temp) && isset($temp->$step))
{
$temp = $temp->$step;
}
elseif (is_array($temp) && isset($temp[$step]))
{
$temp = $temp[$step];
}
else
{
$temp = null;
}
}
$result = $temp;
}
}
foreach ($filters as $filter)
{
$result = $filter($result);
}
return $result;
}
}

670
common/framework/mail.php Normal file
View file

@ -0,0 +1,670 @@
<?php
namespace Rhymix\Framework;
/**
* The mail class.
*/
class Mail
{
/**
* Instance properties.
*/
public $message = null;
public $driver = null;
public $caller = '';
protected $content_type = 'text/html';
protected $attachments = array();
public $errors = array();
protected $sent = false;
/**
* Static properties.
*/
public static $default_driver = null;
public static $custom_drivers = array();
/**
* Set the default driver.
*
* @param object $driver
* @return void
*/
public static function setDefaultDriver(Drivers\MailInterface $driver)
{
self::$default_driver = $driver;
}
/**
* Get the default driver.
*
* @return object
*/
public static function getDefaultDriver()
{
if (!self::$default_driver)
{
$default_driver = config('mail.type');
$default_driver_class = '\\Rhymix\\Framework\\Drivers\Mail\\' . $default_driver;
if (class_exists($default_driver_class))
{
$default_driver_config = config('mail.' . $default_driver) ?: array();
self::$default_driver = $default_driver_class::getInstance($default_driver_config);
}
else
{
self::$default_driver = Drivers\Mail\MailFunction::getInstance(array());
}
}
return self::$default_driver;
}
/**
* Add a custom mail driver.
*/
public static function addDriver(Drivers\MailInterface $driver)
{
self::$custom_drivers[] = $driver;
}
/**
* Get the list of supported mail drivers.
*
* @return array
*/
public static function getSupportedDrivers()
{
$result = array();
foreach (Storage::readDirectory(__DIR__ . '/drivers/mail', false) as $filename)
{
$driver_name = substr($filename, 0, -4);
$class_name = '\Rhymix\Framework\Drivers\Mail\\' . $driver_name;
if ($class_name::isSupported())
{
$result[$driver_name] = array(
'name' => $class_name::getName(),
'required' => $class_name::getRequiredConfig(),
'api_types' => $class_name::getAPITypes(),
'spf_hint' => $class_name::getSPFHint(),
'dkim_hint' => $class_name::getDKIMHint(),
);
}
}
foreach (self::$custom_drivers as $driver)
{
if ($driver->isSupported())
{
$result[strtolower(class_basename($driver))] = array(
'name' => $driver->getName(),
'required' => $driver->getRequiredConfig(),
'api_types' => $driver->getAPITypes(),
'spf_hint' => $class_name::getSPFHint(),
'dkim_hint' => $class_name::getDKIMHint(),
);
}
}
ksort($result);
return $result;
}
/**
* The constructor.
*/
public function __construct()
{
$this->message = \Swift_Message::newInstance();
$this->driver = self::getDefaultDriver();
}
/**
* Set the sender (From:).
*
* @param string $email E-mail address
* @param string $name Name (optional)
* @return bool
*/
public function setFrom($email, $name = null)
{
try
{
$this->message->setFrom($name === null ? $email : array($email => $name));
return true;
}
catch (\Exception $e)
{
$this->errors[] = array($e->getMessage());
return false;
}
}
/**
* Get the sender (From:).
*
* @return string|null
*/
public function getFrom()
{
$list = $this->message->getFrom();
return $list ? array_first($this->formatAddresses($list)) : null;
}
/**
* Add a recipient (To:).
*
* @param string $email E-mail address
* @param string $name Name (optional)
* @return bool
*/
public function addTo($email, $name = null)
{
try
{
$this->message->addTo($email, $name);
return true;
}
catch (\Exception $e)
{
$this->errors[] = array($e->getMessage());
return false;
}
}
/**
* Add a recipient (CC:).
*
* @param string $email E-mail address
* @param string $name Name (optional)
* @return bool
*/
public function addCc($email, $name = null)
{
try
{
$this->message->addCc($email, $name);
return true;
}
catch (\Exception $e)
{
$this->errors[] = array($e->getMessage());
return false;
}
}
/**
* Add a recipient (BCC:).
*
* @param string $email E-mail address
* @param string $name Name (optional)
* @return bool
*/
public function addBcc($email, $name = null)
{
try
{
$this->message->addBcc($email, $name);
return true;
}
catch (\Exception $e)
{
$this->errors[] = array($e->getMessage());
return false;
}
}
/**
* Get the list of recipients.
*
* @return array();
*/
public function getRecipients()
{
$result = array();
foreach ($this->formatAddresses($this->message->getTo()) as $address)
{
$result[] = $address;
}
foreach ($this->formatAddresses($this->message->getCc()) as $address)
{
$result[] = $address;
}
foreach ($this->formatAddresses($this->message->getBcc()) as $address)
{
$result[] = $address;
}
return array_unique($result);
}
/**
* Set the Reply-To: address.
*
* @param string $replyTo
* @return bool
*/
public function setReplyTo($replyTo)
{
try
{
$this->message->setReplyTo(array($replyTo));
return true;
}
catch (\Exception $e)
{
$this->errors[] = array($e->getMessage());
return false;
}
}
/**
* Set the Return-Path: address.
*
* @param string $returnPath
* @return bool
*/
public function setReturnPath($returnPath)
{
try
{
$this->message->setReturnPath($returnPath);
return true;
}
catch (\Exception $e)
{
$this->errors[] = array($e->getMessage());
return false;
}
}
/**
* Set the Message ID.
*
* @param string $messageId
* @return bool
*/
public function setMessageID($messageId)
{
try
{
$headers = $this->message->getHeaders();
$headers->get('Message-ID')->setId($messageId);
return true;
}
catch (\Exception $e)
{
$this->errors[] = array($e->getMessage());
return false;
}
}
/**
* Set the In-Reply-To: header.
*
* @param string $inReplyTo
* @return bool
*/
public function setInReplyTo($inReplyTo)
{
try
{
$headers = $this->message->getHeaders();
$headers->addTextHeader('In-Reply-To', $inReplyTo);
return true;
}
catch (\Exception $e)
{
$this->errors[] = array($e->getMessage());
return false;
}
}
/**
* Set the References: header.
*
* @param string $references
* @return bool
*/
public function setReferences($references)
{
try
{
$headers = $this->message->getHeaders();
$headers->addTextHeader('References', $references);
return true;
}
catch (\Exception $e)
{
$this->errors[] = array($e->getMessage());
return false;
}
}
/**
* Set the subject.
*
* @param string $subject
* @return bool
*/
public function setSubject($subject)
{
try
{
$this->message->setSubject(strval($subject));
return true;
}
catch (\Exception $e)
{
$this->errors[] = array($e->getMessage());
return false;
}
}
/**
* Get the subject.
*
* @return string
*/
public function getSubject()
{
return $this->message->getSubject();
}
/**
* Set the subject (alias to setSubject).
*
* @param string $subject
* @return bool
*/
public function setTitle($subject)
{
return $this->setSubject($subject);
}
/**
* Get the subject (alias to getSubject).
*
* @return string
*/
public function getTitle()
{
return $this->getSubject();
}
/**
* Set the body content.
*
* @param string $content
* @param string $content_type (optional)
* @return void
*/
public function setBody($content, $content_type = null)
{
if ($content_type !== null)
{
$this->setContentType($content_type);
}
if (strpos($this->content_type, 'html') !== false)
{
$content = preg_replace_callback('/<img([^>]+)>/i', array($this, 'convertImageURLs'), $content);
}
$this->message->setBody($content, $this->content_type);
}
/**
* Get the body content.
*
* @return string
*/
public function getBody()
{
return $this->message->getBody();
}
/**
* Set the body content (alias to setBody).
*
* @param string $content
* @param string $content_type (optional)
* @return void
*/
public function setContent($content, $content_type = null)
{
return $this->setBody($content, $content_type);
}
/**
* Get the body content (alias to getBody).
*
* @return string
*/
public function getContent()
{
return $this->getBody();
}
/**
* Set the content type.
*
* @param string $mode The type
* @return void
*/
public function setContentType($type = 'text/html')
{
$this->content_type = (strpos($type, 'html') !== false) ? 'text/html' : ((strpos($type, '/') !== false) ? $type : 'text/plain');
}
/**
* Get the content type.
*
* @return string
*/
public function getContentType()
{
return $this->content_type;
}
/**
* Attach a file.
*
* @param string $local_filename
* @param string $display_filename (optional)
* @return bool
*/
public function attach($local_filename, $display_filename = null)
{
if ($display_filename === null)
{
$display_filename = basename($local_filename);
}
if (!Storage::exists($local_filename))
{
return false;
}
$attachment = \Swift_Attachment::fromPath($local_filename);
$attachment->setFilename($display_filename);
$result = $this->message->attach($attachment);
if ($result)
{
$this->attachments[] = (object)array(
'type' => 'attach',
'local_filename' => $local_filename,
'display_filename' => $display_filename,
'cid' => null,
);
return true;
}
else
{
return false;
}
}
/**
* Embed a file.
*
* @param string $local_filename
* @param string $cid (optional)
* @return string|false
*/
public function embed($local_filename, $cid = null)
{
if (!Storage::exists($local_filename))
{
return false;
}
$embedded = \Swift_EmbeddedFile::fromPath($local_filename);
if ($cid !== null)
{
$embedded->setId(preg_replace('/^cid:/i', '', $cid));
}
$result = $this->message->embed($embedded);
if ($result)
{
$this->attachments[] = (object)array(
'type' => 'embed',
'local_filename' => $local_filename,
'display_filename' => null,
'cid' => $result,
);
return $result;
}
else
{
return false;
}
}
/**
* Get the list of attachments to this message.
*
* @return array
*/
public function getAttachments()
{
return $this->attachments;
}
/**
* Send the email.
*
* @return bool
*/
public function send()
{
// Get caller information.
$backtrace = debug_backtrace(0);
if(count($backtrace) && isset($backtrace[0]['file']))
{
$this->caller = $backtrace[0]['file'] . ($backtrace[0]['line'] ? (' line ' . $backtrace[0]['line']) : '');
}
// Reset Message-ID in case send() is called multiple times.
$random = substr(hash('sha256', mt_rand() . microtime() . getmypid()), 0, 32);
$sender = $this->message->getFrom(); reset($sender);
$id = $random . '@' . (preg_match('/^(.+)@([^@]+)$/', key($sender), $matches) ? $matches[2] : 'swift.generated');
$this->message->getHeaders()->get('Message-ID')->setId($id);
$output = \ModuleHandler::triggerCall('mail.send', 'before', $this);
if(!$output->toBool())
{
$this->errors[] = $output->getMessage();
return false;
}
try
{
$this->sent = $this->driver->send($this) ? true : false;
}
catch(\Exception $e)
{
$this->errors[] = $e->getMessage();
$this->sent = false;
}
$output = \ModuleHandler::triggerCall('mail.send', 'after', $this);
if(!$output->toBool())
{
$this->errors[] = $output->getMessage();
}
return $this->sent;
}
/**
* Check if the message was sent.
*
* @return bool
*/
public function isSent()
{
return $this->sent;
}
/**
* Get caller information.
*
* @return string
*/
public function getCaller()
{
return $this->caller;
}
/**
* Get errors.
*
* @return array
*/
public function getErrors()
{
return $this->errors;
}
/**
* Convert image paths to absolute URLs.
*
* @see Mail::setContent()
* @param array $matches Match info.
* @return string
*/
protected function convertImageURLs(array $matches)
{
return preg_replace('/src=(["\']?)files/i', 'src=$1' . URL::getCurrentDomainURL(\RX_BASEURL) . 'files', $matches[0]);
}
/**
* Format an array of addresses for display.
*
* @param array $addresses
* @return array
*/
protected function formatAddresses($addresses)
{
$result = array();
if (!$addresses)
{
return array();
}
foreach($addresses as $email => $name)
{
if(strval($name) === '')
{
$result[] = $email;
}
else
{
$result[] = $name . ' <' . $email . '>';
}
}
return $result;
}
}

View file

@ -23,6 +23,7 @@
"ezyang/htmlpurifier": "4.7.*",
"hautelook/phpass": "0.3.*",
"jbbcode/jbbcode": "1.3.*",
"jmhobbs/swiftmailer-transport-aws-ses": "0.9.*",
"leafo/lessphp": "0.5.*",
"leafo/scssphp": "0.6.*",
"league/html-to-markdown": "4.2.*",

70
composer.lock generated
View file

@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "ff1a5bab9497b1e5f25dd3069ffbbf13",
"content-hash": "9478a148fd56f1f50543063e3971a777",
"hash": "64d8278cd705dec01a94208e378716f8",
"content-hash": "fa544ace96d8d80c11db9dafb2c49753",
"packages": [
{
"name": "defuse/php-encryption",
@ -186,6 +186,49 @@
],
"time": "2014-07-06 05:48:20"
},
{
"name": "jmhobbs/swiftmailer-transport-aws-ses",
"version": "0.9.2",
"source": {
"type": "git",
"url": "https://github.com/jmhobbs/Swiftmailer-Transport--AWS-SES.git",
"reference": "10110a450225a19b5095e7313a5c7c4b43bba3b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jmhobbs/Swiftmailer-Transport--AWS-SES/zipball/10110a450225a19b5095e7313a5c7c4b43bba3b6",
"reference": "10110a450225a19b5095e7313a5c7c4b43bba3b6",
"shasum": ""
},
"require": {
"php": ">=5.2.0",
"swiftmailer/swiftmailer": ">=4.0.0"
},
"type": "library",
"autoload": {
"psr-0": {
"": "classes/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "John Hobbs",
"email": "john@velvetcache.org"
}
],
"description": "Add AWS SES support to Swiftmailer",
"keywords": [
"aws",
"email",
"ses",
"swiftmailer"
],
"time": "2014-11-12 23:51:28"
},
{
"name": "leafo/lessphp",
"version": "v0.5.0",
@ -402,16 +445,16 @@
},
{
"name": "matthiasmullie/path-converter",
"version": "1.0.7",
"version": "1.0.8",
"source": {
"type": "git",
"url": "https://github.com/matthiasmullie/path-converter.git",
"reference": "83609c1bb251b2540eba912615571a501a0a06a6"
"reference": "7c36e5cafa95dd20008d19b153b506cffa8c2848"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/matthiasmullie/path-converter/zipball/83609c1bb251b2540eba912615571a501a0a06a6",
"reference": "83609c1bb251b2540eba912615571a501a0a06a6",
"url": "https://api.github.com/repos/matthiasmullie/path-converter/zipball/7c36e5cafa95dd20008d19b153b506cffa8c2848",
"reference": "7c36e5cafa95dd20008d19b153b506cffa8c2848",
"shasum": ""
},
"require": {
@ -419,8 +462,7 @@
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "~4.8",
"satooshi/php-coveralls": "~1.0"
"phpunit/phpunit": "~4.8"
},
"type": "library",
"autoload": {
@ -448,7 +490,7 @@
"paths",
"relative"
],
"time": "2016-01-07 00:41:13"
"time": "2016-04-27 10:38:05"
},
{
"name": "michelf/php-markdown",
@ -650,16 +692,16 @@
},
{
"name": "swiftmailer/swiftmailer",
"version": "v5.4.1",
"version": "v5.4.2",
"source": {
"type": "git",
"url": "https://github.com/swiftmailer/swiftmailer.git",
"reference": "0697e6aa65c83edf97bb0f23d8763f94e3f11421"
"reference": "d8db871a54619458a805229a057ea2af33c753e8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/0697e6aa65c83edf97bb0f23d8763f94e3f11421",
"reference": "0697e6aa65c83edf97bb0f23d8763f94e3f11421",
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/d8db871a54619458a805229a057ea2af33c753e8",
"reference": "d8db871a54619458a805229a057ea2af33c753e8",
"shasum": ""
},
"require": {
@ -699,7 +741,7 @@
"mail",
"mailer"
],
"time": "2015-06-06 14:19:39"
"time": "2016-05-01 08:45:47"
},
{
"name": "true/punycode",

View file

@ -0,0 +1,306 @@
<?php
/**
* @file advanced_mailer.admin.controller.php
* @author Kijin Sung <kijin@kijinsung.com>
* @license GPLv2 or Later <https://www.gnu.org/licenses/gpl-2.0.html>
* @brief Advanced Mailer Admin Controller
*/
class Advanced_MailerAdminController extends Advanced_Mailer
{
/**
* Save the basic configuration.
*/
public function procAdvanced_MailerAdminInsertConfig()
{
// Get and validate the new configuration.
$vars = Context::getRequestVars();
if (!$vars->sender_name)
{
return new Object(-1, 'msg_advanced_mailer_sender_name_is_empty');
}
if (!$vars->sender_email)
{
return new Object(-1, 'msg_advanced_mailer_sender_email_is_empty');
}
if (!Mail::isVaildMailAddress($vars->sender_email))
{
return new Object(-1, 'msg_advanced_mailer_sender_email_is_invalid');
}
if ($vars->reply_to && !Mail::isVaildMailAddress($vars->reply_to))
{
return new Object(-1, 'msg_advanced_mailer_reply_to_is_invalid');
}
// Validate the sending method.
$sending_methods = Rhymix\Framework\Mail::getSupportedDrivers();
$sending_method = $vars->sending_method;
if (!array_key_exists($sending_method, $sending_methods))
{
return new Object(-1, 'msg_advanced_mailer_sending_method_is_invalid');
}
// Validate the configuration for the selected sending method.
$sending_method_config = array();
foreach ($sending_methods[$sending_method]['required'] as $conf_name)
{
$conf_value = $vars->{$sending_method . '_' . $conf_name} ?: null;
if (!$conf_value)
{
return new Object(-1, 'msg_advanced_mailer_smtp_host_is_invalid');
}
$sending_method_config[$conf_name] = $conf_value;
}
// Update the current module's configuration.
$config = $this->getConfig();
$config->sender_name = $vars->sender_name;
$config->sender_email = $vars->sender_email;
$config->reply_to = $vars->reply_to;
$config->force_sender = toBool($vars->force_sender);
$config->log_sent_mail = toBool($vars->log_sent_mail);
$config->log_errors = toBool($vars->log_errors);
$output = getController('module')->insertModuleConfig('advanced_mailer', $config);
if ($output->toBool())
{
$this->setMessage('success_registed');
}
else
{
return $output;
}
// Update the webmaster's name and email in the member module.
getController('module')->updateModuleConfig('member', (object)array(
'webmaster_name' => $config->sender_name,
'webmaster_email' => $config->sender_email,
));
// Update system configuration.
Rhymix\Framework\Config::set("mail.type", $sending_method);
Rhymix\Framework\Config::set("mail.$sending_method", $sending_method_config);
Rhymix\Framework\Config::save();
if (Context::get('success_return_url'))
{
$this->setRedirectUrl(Context::get('success_return_url'));
}
else
{
$this->setRedirectUrl(getNotEncodedUrl('', 'module', 'admin', 'act', 'dispAdvanced_mailerAdminConfig'));
}
}
/**
* Save the exception configuration.
*/
public function procAdvanced_MailerAdminInsertExceptions()
{
// Get the current configuration.
$config = $this->getConfig();
$sending_methods = Rhymix\Framework\Mail::getSupportedDrivers();
// Get and validate the list of exceptions.
$exceptions = array();
for ($i = 1; $i <= 3; $i++)
{
$method = strval(Context::get('exception_' . $i . '_method'));
$domains = trim(Context::get('exception_' . $i . '_domains'));
if ($method !== '' && $domains !== '')
{
if ($method !== 'default' && !isset($sending_methods[$method]))
{
return new Object(-1, 'msg_advanced_mailer_sending_method_is_invalid');
}
if ($method !== 'default')
{
foreach ($this->sending_methods[$method]['required'] as $conf_name)
{
if (!Rhymix\Framework\Config::get("mail.$method.$conf_name"))
{
return new Object(-1, sprintf(
Context::getLang('msg_advanced_mailer_sending_method_is_not_configured'),
Context::getLang('cmd_advanced_mailer_sending_method_' . $method)));
}
}
}
$exceptions[$i]['method'] = $method;
$exceptions[$i]['domains'] = array();
$domains = array_map('trim', preg_split('/[,\n]/', $domains, null, PREG_SPLIT_NO_EMPTY));
foreach ($domains as $domain)
{
if (strpos($domain, 'xn--') !== false)
{
$domain = Rhymix\Framework\URL::decodeIdna($domain);
}
$exceptions[$i]['domains'][] = $domain;
}
}
}
// Save the new configuration.
$config->exceptions = $exceptions;
$output = getController('module')->insertModuleConfig('advanced_mailer', $config);
if ($output->toBool())
{
$this->setMessage('success_registed');
}
else
{
return $output;
}
if (Context::get('success_return_url'))
{
$this->setRedirectUrl(Context::get('success_return_url'));
}
else
{
$this->setRedirectUrl(getNotEncodedUrl('', 'module', 'admin', 'act', 'dispAdvanced_mailerAdminExceptions'));
}
}
/**
* Check the DNS record of a domain.
*/
public function procAdvanced_MailerAdminCheckDNSRecord()
{
$check_config = Context::gets('hostname', 'record_type');
if (!preg_match('/^[a-z0-9_.-]+$/', $check_config->hostname))
{
$this->add('record_content', false);
return;
}
if (!defined('DNS_' . $check_config->record_type))
{
$this->add('record_content', false);
return;
}
$records = @dns_get_record($check_config->hostname, constant('DNS_' . $check_config->record_type));
if ($records === false)
{
$this->add('record_content', false);
return;
}
$return_values = array();
foreach ($records as $record)
{
if (isset($record[strtolower($check_config->record_type)]))
{
$return_values[] = $record[strtolower($check_config->record_type)];
}
}
$this->add('record_content', implode("\n\n", $return_values));
return;
}
/**
* Clear old sending log.
*/
public function procAdvanced_mailerAdminClearSentMail()
{
$status = Context::get('status');
$clear_before_days = intval(Context::get('clear_before_days'));
if (!in_array($status, array('success', 'error')))
{
return new Object(-1, 'msg_invalid_request');
}
if ($clear_before_days < 0)
{
return new Object(-1, 'msg_invalid_request');
}
$obj = new stdClass();
$obj->status = $status;
$obj->regdate = date('YmdHis', time() - ($clear_before_days * 86400) + zgap());
$output = executeQuery('advanced_mailer.deleteLogs', $obj);
if ($status === 'success')
{
$this->setRedirectUrl(getNotEncodedUrl('', 'module', 'admin', 'act', 'dispAdvanced_mailerAdminSentMail'));
}
else
{
$this->setRedirectUrl(getNotEncodedUrl('', 'module', 'admin', 'act', 'dispAdvanced_mailerAdminErrors'));
}
}
/**
* Send a test email using a temporary configuration.
*/
public function procAdvanced_MailerAdminTestSend()
{
$advanced_mailer_config = $this->getConfig();
$recipient_config = Context::gets('recipient_name', 'recipient_email');
$recipient_name = $recipient_config->recipient_name;
$recipient_email = $recipient_config->recipient_email;
if (!$recipient_name)
{
$this->add('test_result', 'Error: ' . Context::getLang('msg_advanced_mailer_recipient_name_is_empty'));
return;
}
if (!$recipient_email)
{
$this->add('test_result', 'Error: ' . Context::getLang('msg_advanced_mailer_recipient_email_is_empty'));
return;
}
if (!Mail::isVaildMailAddress($recipient_email))
{
$this->add('test_result', 'Error: ' . Context::getLang('msg_advanced_mailer_recipient_email_is_invalid'));
return;
}
$oAdvancedMailerController = getController('advanced_mailer');
$sending_method = $oAdvancedMailerController->getSendingMethodForEmailAddress($recipient_email) ?: config('mail.type');
try
{
$oMail = new Rhymix\Framework\Mail();
$oMail->setTitle('Advanced Mailer Test : ' . strtoupper($sending_method));
$oMail->setContent('<p>This is a <b>test email</b> from Advanced Mailer.</p><p>Thank you for trying Advanced Mailer.</p>' .
'<p>고급 메일 발송 모듈 <b>테스트</b> 메일입니다.</p><p>메일이 정상적으로 발송되고 있습니다.</p>');
$oMail->addTo($recipient_email, $recipient_name);
$result = $oMail->send();
if (!$result)
{
if (count($oMail->errors))
{
if (config('mail.type') === 'smtp')
{
if (strpos(config('mail.smtp.smtp_host'), 'gmail.com') !== false && strpos(implode("\n", $oMail->errors), 'code "535"') !== false)
{
$this->add('test_result', Context::getLang('msg_advanced_mailer_google_account_security'));
return;
}
if (strpos(config('mail.smtp.smtp_host'), 'naver.com') !== false && strpos(implode("\n", $oMail->errors), 'Failed to authenticate') !== false)
{
$this->add('test_result', Context::getLang('msg_advanced_mailer_naver_smtp_disabled'));
return;
}
}
$this->add('test_result', nl2br(htmlspecialchars(implode("\n", $oMail->errors))));
return;
}
else
{
$this->add('test_result', Context::getLang('msg_advanced_mailer_unknown_error'));
return;
}
}
}
catch (Exception $e)
{
$this->add('test_result', nl2br(htmlspecialchars($e->getMessage())));
return;
}
$this->add('test_result', Context::getLang('msg_advanced_mailer_test_success'));
return;
}
}

View file

@ -0,0 +1,262 @@
<?php
/**
* @file advanced_mailer.admin.view.php
* @author Kijin Sung <kijin@kijinsung.com>
* @license GPLv2 or Later <https://www.gnu.org/licenses/gpl-2.0.html>
* @brief Advanced Mailer Admin View
*/
class Advanced_MailerAdminView extends Advanced_Mailer
{
/**
* Display the general configuration form.
*/
public function dispAdvanced_MailerAdminConfig()
{
$advanced_mailer_config = $this->getConfig();
$member_config = getModel('module')->getModuleConfig('member');
$sending_methods = Rhymix\Framework\Mail::getSupportedDrivers();
Context::set('advanced_mailer_config', $advanced_mailer_config);
Context::set('sending_methods', $sending_methods);
Context::set('sending_method', config('mail.type'));
Context::set('webmaster_name', $member_config->webmaster_name ? $member_config->webmaster_name : 'webmaster');
Context::set('webmaster_email', $member_config->webmaster_email);
$this->setTemplatePath($this->module_path.'tpl');
$this->setTemplateFile('config');
}
/**
* Display the exception domains configuration form.
*/
public function dispAdvanced_MailerAdminExceptions()
{
$advanced_mailer_config = $this->getConfig();
$sending_methods = Rhymix\Framework\Mail::getSupportedDrivers();
for ($i = 1; $i <= 3; $i++)
{
if (!isset($advanced_mailer_config->exceptions[$i]))
{
$advanced_mailer_config->exceptions[$i] = array('method' => '', 'domains' => array());
}
elseif ($advanced_mailer_config->exceptions[$i]['method'] === 'mail')
{
$advanced_mailer_config->exceptions[$i]['method'] = 'mailfunction';
}
}
Context::set('advanced_mailer_config', $advanced_mailer_config);
Context::set('sending_methods', $sending_methods);
Context::set('sending_method', config('mail.type'));
$this->setTemplatePath($this->module_path.'tpl');
$this->setTemplateFile('exceptions');
}
/**
* Display the SPF/DKIM setting guide.
*/
public function dispAdvanced_MailerAdminSpfDkim()
{
$advanced_mailer_config = $this->getConfig();
$sending_methods = Rhymix\Framework\Mail::getSupportedDrivers();
Context::set('advanced_mailer_config', $advanced_mailer_config);
Context::set('sending_methods', $sending_methods);
Context::set('sending_method', config('mail.type'));
if (strpos($advanced_mailer_config->sender_email, '@') !== false)
{
Context::set('sending_domain', substr(strrchr($advanced_mailer_config->sender_email, '@'), 1));
}
else
{
Context::set('sending_domain', preg_replace('/^www\./', '', $_SERVER['HTTP_HOST']));
}
$used_methods = array(config('mail.type'));
$advanced_mailer_config->exceptions = $advanced_mailer_config->exceptions ?: array();
foreach ($advanced_mailer_config->exceptions as $exception)
{
if ($exception['method'] !== 'default' && $exception['method'] !== $used_methods[0] && count($exception['domains']))
{
$used_methods[] = $exception['method'];
}
}
Context::set('used_methods', $used_methods);
$used_methods_with_usable_spf = array();
$used_methods_with_usable_dkim = array();
foreach ($used_methods as $method)
{
if ($method === 'woorimail' && config('mail.woorimail.api_type') === 'free') continue;
if ($sending_methods[$method]['spf_hint'])
{
if (strpos($sending_methods[$method]['spf_hint'], '$SERVER_ADDR') !== false)
{
$used_methods_with_usable_spf[$method] = strtr($sending_methods[$method]['spf_hint'], array('$SERVER_ADDR' => $this->getServerIP()));
}
else
{
$used_methods_with_usable_spf[$method] = $sending_methods[$method]['spf_hint'];
}
}
if ($sending_methods[$method]['dkim_hint'])
{
$used_methods_with_usable_dkim[$method] = $sending_methods[$method]['dkim_hint'];
}
}
ksort($used_methods_with_usable_spf);
ksort($used_methods_with_usable_dkim);
Context::set('used_methods_with_usable_spf', $used_methods_with_usable_spf);
Context::set('used_methods_with_usable_dkim', $used_methods_with_usable_dkim);
$this->setTemplatePath($this->module_path.'tpl');
$this->setTemplateFile('spf_dkim');
}
/**
* Display the test send form.
*/
public function dispAdvanced_MailerAdminTestConfig()
{
$advanced_mailer_config = $this->getConfig();
$sending_methods = Rhymix\Framework\Mail::getSupportedDrivers();
Context::set('advanced_mailer_config', $advanced_mailer_config);
Context::set('sending_methods', $sending_methods);
Context::set('sending_method', config('mail.type'));
$this->setTemplatePath($this->module_path.'tpl');
$this->setTemplateFile('test');
}
/**
* Display the sent mail log.
*/
public function dispAdvanced_MailerAdminSentMail()
{
$obj = new stdClass();
$obj->status = 'success';
$obj->page = $page = Context::get('page') ?: 1;
$maillog = executeQuery('advanced_mailer.getLogByType', $obj);
$maillog = $maillog->toBool() ? $this->procMailLog($maillog->data) : array();
Context::set('advanced_mailer_log', $maillog);
Context::set('advanced_mailer_status', 'success');
$paging = $this->procPaging('success', $page);
Context::set('total_count', $paging->total_count);
Context::set('total_page', $paging->total_page);
Context::set('page', $paging->page);
Context::set('page_navigation', $paging->page_navigation);
$sending_methods = Rhymix\Framework\Mail::getSupportedDrivers();
Context::set('sending_methods', $sending_methods);
$this->setTemplatePath($this->module_path.'tpl');
$this->setTemplateFile('view_log');
}
/**
* Display the error log.
*/
public function dispAdvanced_MailerAdminErrors()
{
$obj = new stdClass();
$obj->status = 'error';
$obj->page = $page = Context::get('page') ?: 1;
$maillog = executeQuery('advanced_mailer.getLogByType', $obj);
$maillog = $maillog->toBool() ? $this->procMailLog($maillog->data) : array();
Context::set('advanced_mailer_log', $maillog);
Context::set('advanced_mailer_status', 'error');
$paging = $this->procPaging('error', $page);
Context::set('total_count', $paging->total_count);
Context::set('total_page', $paging->total_page);
Context::set('page', $paging->page);
Context::set('page_navigation', $paging->page_navigation);
$sending_methods = Rhymix\Framework\Mail::getSupportedDrivers();
Context::set('sending_methods', $sending_methods);
$this->setTemplatePath($this->module_path.'tpl');
$this->setTemplateFile('view_log');
}
/**
* Process mail log for display.
*/
public function procMailLog($log)
{
foreach($log as $item)
{
$from = explode("\n", $item->mail_from);
foreach($from as &$fromitem)
{
if(preg_match('/^(.+) <([^>]+)>$/', $fromitem, $matches))
{
$fromitem = array($matches[2], $matches[1]);
}
else
{
$fromitem = array($fromitem, '');
}
}
$item->mail_from = $from;
$to = explode("\n", $item->mail_to);
foreach($to as &$toitem)
{
if(preg_match('/^(.+?) <([^>]+)>$/', $toitem, $matches))
{
$toitem = array($matches[2], $matches[1]);
}
else
{
$toitem = array($toitem, '');
}
}
$item->mail_to = $to;
}
return $log;
}
/**
* Process paging.
*/
public function procPaging($status, $page = 1)
{
$args = new stdClass;
$args->status = $status;
$count = executeQuery('advanced_mailer.countLogByType', $args);
$total_count = $count->data->count;
$total_page = max(1, ceil($total_count / 20));
$output = new Object();
$output->total_count = $total_count;
$output->total_page = $total_page;
$output->page = $page;
$output->page_navigation = new PageHandler($total_count, $total_page, $page, 10);
return $output;
}
/**
* Get the public IPv4 address of the current server.
*/
public function getServerIP()
{
if (isset($_SESSION['advanced_mailer_ip_cache']) && $_SESSION['advanced_mailer_ip_cache'][1] > time() - 3600)
{
return $_SESSION['advanced_mailer_ip_cache'][0];
}
else
{
$ip = trim(FileHandler::getRemoteResource('http://icanhazip.com/'));
$ip = preg_match('/^[0-9]+(\.[0-9]+){3}$/', $ip) ? $ip : false;
$_SESSION['advanced_mailer_ip_cache'] = array($ip, time());
return $ip;
}
}
}

View file

@ -0,0 +1,244 @@
<?php
/**
* @file advanced_mailer.class.php
* @author Kijin Sung <kijin@kijinsung.com>
* @license GPLv2 or Later <https://www.gnu.org/licenses/gpl-2.0.html>
* @brief Advanced Mailer Main Class
*/
class Advanced_Mailer extends ModuleObject
{
/**
* Get the configuration of the current module.
*/
public function getConfig()
{
$config = getModel('module')->getModuleConfig('advanced_mailer');
if (!is_object($config))
{
$config = new stdClass();
}
if (isset($config->is_enabled) || isset($config->sending_method) || isset($config->send_type))
{
$config = $this->migrateConfig($config);
getController('module')->insertModuleConfig('advanced_mailer', $config);
}
return $config;
}
/**
* Migrate from previous configuration format.
*/
public function migrateConfig($config)
{
$systemconfig = array();
if (isset($config->sending_method))
{
$systemconfig['mail.type'] = $config->sending_method;
}
elseif (isset($config->send_type))
{
$systemconfig['mail.type'] = $config->send_type;
}
if ($systemconfig['mail.type'] === 'mail')
{
$systemconfig['mail.type'] = 'mailfunction';
}
if (isset($config->username))
{
if (in_array('username', $this->sending_methods[$config->sending_method]['conf']))
{
$config->{$config->sending_method . '_username'} = $config->username;
}
unset($config->username);
}
if (isset($config->password))
{
if (in_array('password', $this->sending_methods[$config->sending_method]['conf']))
{
$config->{$config->sending_method . '_password'} = $config->password;
}
unset($config->password);
}
if (isset($config->domain))
{
if (in_array('domain', $this->sending_methods[$config->sending_method]['conf']))
{
$config->{$config->sending_method . '_domain'} = $config->domain;
}
unset($config->domain);
}
if (isset($config->api_key))
{
if (in_array('api_key', $this->sending_methods[$config->sending_method]['conf']))
{
$config->{$config->sending_method . '_api_key'} = $config->api_key;
}
unset($config->api_key);
}
if (isset($config->account_type))
{
if (in_array('account_type', $this->sending_methods[$config->sending_method]['conf']))
{
$config->{$config->sending_method . '_account_type'} = $config->account_type;
}
unset($config->account_type);
}
if (isset($config->aws_region))
{
$config->ses_region = $config->aws_region;
unset($config->aws_region);
}
if (isset($config->aws_access_key))
{
$config->ses_access_key = $config->aws_access_key;
unset($config->aws_access_key);
}
if (isset($config->aws_secret_key))
{
$config->ses_secret_key = $config->aws_secret_key;
unset($config->aws_secret_key);
}
$mail_drivers = Rhymix\Framework\Mail::getSupportedDrivers();
foreach ($mail_drivers as $driver_name => $driver_definition)
{
foreach ($config as $key => $value)
{
if (strncmp($key, $driver_name . '_', strlen($driver_name) + 1) === 0)
{
$subkey = substr($key, strlen($driver_name) + 1);
switch ($subkey)
{
case 'host':
case 'port':
case 'security':
$systemconfig["mail.$driver_name.smtp_" . $subkey] = $value;
break;
case 'username':
case 'password':
$systemconfig["mail.$driver_name." . ($driver_name === 'smtp' ? 'smtp_' : 'api_') . substr($subkey, 0, 4)] = $value;
break;
case 'account_type':
case 'region':
$systemconfig["mail.$driver_name.api_type"] = $value;
break;
case 'access_key':
$systemconfig["mail.$driver_name.api_user"] = $value;
break;
case 'secret_key':
$systemconfig["mail.$driver_name.api_pass"] = $value;
break;
case 'domain':
$systemconfig["mail.$driver_name.api_domain"] = $value;
break;
case 'api_key':
$systemconfig["mail.$driver_name.api_token"] = $value;
break;
default:
break;
}
unset($config->$key);
}
}
}
if (count($systemconfig))
{
foreach ($systemconfig as $key => $value)
{
Rhymix\Framework\Config::set($key, $value);
}
Rhymix\Framework\Config::save();
}
unset($config->is_enabled);
unset($config->sending_method);
unset($config->send_type);
$config->log_sent_mail = toBool($config->log_sent_mail);
$config->log_errors = toBool($config->log_errors);
$config->force_sender = toBool($config->force_sender);
if (!isset($config->exceptions))
{
$config->exceptions = array();
}
return $config;
}
/**
* Register triggers.
*/
public function registerTriggers()
{
$oModuleModel = getModel('module');
$oModuleController = getController('module');
if ($oModuleModel->getTrigger('moduleHandler.init', 'advanced_mailer', 'model', 'triggerReplaceMailClass', 'before'))
{
$oModuleController->deleteTrigger('moduleHandler.init', 'advanced_mailer', 'model', 'triggerReplaceMailClass', 'before');
}
if (!$oModuleModel->getTrigger('mail.send', 'advanced_mailer', 'controller', 'triggerBeforeMailSend', 'before'))
{
$oModuleController->insertTrigger('mail.send', 'advanced_mailer', 'controller', 'triggerBeforeMailSend', 'before');
}
if (!$oModuleModel->getTrigger('mail.send', 'advanced_mailer', 'controller', 'triggerAfterMailSend', 'after'))
{
$oModuleController->insertTrigger('mail.send', 'advanced_mailer', 'controller', 'triggerAfterMailSend', 'after');
}
}
/**
* Install.
*/
public function moduleInstall()
{
$this->registerTriggers();
return new Object();
}
/**
* Check update.
*/
public function checkUpdate()
{
$oModuleModel = getModel('module');
if ($oModuleModel->getTrigger('moduleHandler.init', 'advanced_mailer', 'model', 'triggerReplaceMailClass', 'before'))
{
return true;
}
if (!$oModuleModel->getTrigger('mail.send', 'advanced_mailer', 'controller', 'triggerBeforeMailSend', 'before'))
{
return true;
}
if (!$oModuleModel->getTrigger('mail.send', 'advanced_mailer', 'controller', 'triggerAfterMailSend', 'after'))
{
return true;
}
return false;
}
/**
* Update.
*/
public function moduleUpdate()
{
$this->registerTriggers();
return new Object(0, 'success_updated');
}
public function recompileCache()
{
// no-op
}
}

View file

@ -0,0 +1,148 @@
<?php
/**
* @file advanced_mailer.controller.php
* @author Kijin Sung <kijin@kijinsung.com>
* @license GPLv2 or Later <https://www.gnu.org/licenses/gpl-2.0.html>
* @brief Advanced Mailer Model
*/
class Advanced_MailerController extends Advanced_Mailer
{
/**
* Before mail send trigger.
*/
public function triggerBeforeMailSend($mail)
{
$config = $this->getConfig();
$first_recipient = array_first_key($mail->message->getTo());
if ($exception_driver = $this->getSendingMethodForEmailAddress($first_recipient, $config))
{
$driver_class = '\\Rhymix\\Framework\\Drivers\Mail\\' . $exception_driver;
if (class_exists($driver_class))
{
$mail->driver = $driver_class::getInstance(config("mail.$exception_driver"));
}
}
if (!$mail->getFrom())
{
$mail->setFrom($config->sender_email, $config->sender_name ?: null);
}
elseif (toBool($config->force_sender))
{
if (stripos($mail->driver->getName(), 'woorimail') !== false && config('mail.woorimail.api_type') === 'free')
{
// no-op
}
else
{
$original_sender_email = array_first_key($mail->message->getFrom());
$original_sender_name = array_first($mail->message->getFrom());
if ($original_sender_email !== $config->sender_email)
{
$mail->setFrom($config->sender_email, $original_sender_name ?: $config->sender_name);
$mail->setReplyTo($original_sender_email);
}
}
}
}
/**
* After mail send trigger.
*/
public function triggerAfterMailSend($mail)
{
$config = $this->getConfig();
if (toBool($config->log_sent_mail) || (toBool(self::$config->log_errors) && count($mail->errors)))
{
$obj = new \stdClass();
$obj->mail_srl = getNextSequence();
$obj->mail_from = '';
$obj->mail_to = '';
if ($real_sender = $mail->message->getFrom())
{
foreach($real_sender as $email => $name)
{
$obj->mail_from .= (strval($name) !== '' ? "$name <$email>" : $email) . "\n";
}
}
if ($real_to = $mail->message->getTo())
{
foreach($real_to as $email => $name)
{
$obj->mail_to .= (strval($name) !== '' ? "$name <$email>" : $email) . "\n";
}
}
if ($real_cc = $mail->message->getCc())
{
foreach($real_cc as $email => $name)
{
$obj->mail_to .= (strval($name) !== '' ? "$name <$email>" : $email) . "\n";
}
}
if ($real_bcc = $mail->message->getBcc())
{
foreach($real_bcc as $email => $name)
{
$obj->mail_to .= (strval($name) !== '' ? "$name <$email>" : $email) . "\n";
}
}
$obj->mail_from = trim($obj->mail_from);
$obj->mail_to = trim($obj->mail_to);
$obj->subject = $mail->message->getSubject();
$obj->calling_script = $mail->getCaller();
$obj->sending_method = strtolower(class_basename($mail->driver));
$obj->status = !count($mail->errors) ? 'success' : 'error';
$obj->errors = count($mail->errors) ? implode("\n", $mail->errors) : null;
$output = executeQuery('advanced_mailer.insertLog', $obj);
if (!$output->toBool())
{
return $output;
}
}
}
/**
* Check if an email address is on a list of exceptions.
*
* @param string $email
* @param object $config (optional)
* @return string|null
*/
public function getSendingMethodForEmailAddress($email, $config = null)
{
if (!$config)
{
$config = $this->getConfig();
}
if (!isset($config->exceptions) || !is_array($config->exceptions) || !count($config->exceptions))
{
return null;
}
$email = Rhymix\Framework\URL::encodeIdna($email);
foreach ($config->exceptions as $exception)
{
$domains = array();
foreach ($exception['domains'] as $domain)
{
$domains[] = preg_quote($domain, '/');
}
if (count($domains) && preg_match('/\b(?:' . implode('|', $domains) . ')$/i', $email))
{
return $exception['method'];
}
}
return null;
}
}

View file

@ -0,0 +1,18 @@
<?php
/**
* @file advanced_mailer.model.php
* @author Kijin Sung <kijin@kijinsung.com>
* @license GPLv2 or Later <https://www.gnu.org/licenses/gpl-2.0.html>
* @brief Advanced Mailer Model
*/
class Advanced_MailerModel extends Advanced_Mailer
{
/**
* @deprecated
*/
public function triggerReplaceMailClass()
{
}
}

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="0.2">
<title xml:lang="ko">고급 메일 발송 모듈</title>
<title xml:lang="en">Advanced Mailer</title>
<description xml:lang="ko">
외부 SMTP 서버 또는 API를 사용하여 메일을 발송합니다.
</description>
<description xml:lang="en">
Send mail using an external SMTP server or API service.
</description>
<version>2.0.0</version>
<date>2016-05-22</date>
<author email_address="kijin@kijinsung.com" link="https://github.com/kijin">
<name xml:lang="ko">Kijin Sung</name>
<name xml:lang="en">Kijin Sung</name>
</author>
</module>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<module>
<grants />
<permissions />
<actions>
<action name="dispAdvanced_mailerAdminConfig" type="view" admin_index="true" menu_name="advanced_mailer" />
<action name="dispAdvanced_mailerAdminExceptions" type="view" />
<action name="dispAdvanced_mailerAdminSpfDkim" type="view" />
<action name="dispAdvanced_mailerAdminTestConfig" type="view" />
<action name="dispAdvanced_mailerAdminSentMail" type="view" />
<action name="dispAdvanced_mailerAdminErrors" type="view" />
<action name="procAdvanced_mailerAdminInsertConfig" type="controller" />
<action name="procAdvanced_mailerAdminInsertExceptions" type="controller" />
<action name="procAdvanced_mailerAdminCheckDNSRecord" type="controller" />
<action name="procAdvanced_mailerAdminClearSentMail" type="controller" />
<action name="procAdvanced_mailerAdminTestSend" type="controller" />
</actions>
<menus>
<menu name="advanced_mailer" type="all">
<title xml:lang="ko">고급 메일 발송 모듈</title>
<title xml:lang="en">Advanced Mailer</title>
</menu>
</menus>
</module>

View file

@ -0,0 +1,114 @@
<?php
$lang->cmd_advanced_mailer = 'Advanced Mailer';
$lang->cmd_advanced_mailer_general_config = 'General settings';
$lang->cmd_advanced_mailer_is_enabled = 'Enable module';
$lang->cmd_advanced_mailer_is_enabled_yes = 'Enabled';
$lang->cmd_advanced_mailer_is_enabled_no = 'Disabled';
$lang->cmd_advanced_mailer_logging = 'Logging';
$lang->cmd_advanced_mailer_log_sent_mail = 'Log Sent Mail';
$lang->cmd_advanced_mailer_log_errors = 'Log Errors';
$lang->cmd_advanced_mailer_log_yes = 'Yes';
$lang->cmd_advanced_mailer_log_no = 'No';
$lang->cmd_advanced_mailer_sending_method_config = 'Default Sending Method';
$lang->cmd_advanced_mailer_about_sending_method_config = 'Please fill all of the boxes.';
$lang->cmd_advanced_mailer_sending_method = 'Sending method';
$lang->cmd_advanced_mailer_about_sending_method = 'This method will be used for all emails where the recipient\'s email address does not belong to an <a href="./index.php?module=admin&amp;act=dispAdvanced_mailerAdminExceptions" target="_blank">exception domain</a>.';
$lang->cmd_advanced_mailer_sending_method_default = 'Default sending method';
$lang->cmd_advanced_mailer_sending_method_exceptions = 'Exceptions';
$lang->cmd_advanced_mailer_smtp_manual_entry = 'Manual entry';
$lang->cmd_advanced_mailer_smtp_host = 'SMTP host';
$lang->cmd_advanced_mailer_smtp_port = 'SMTP port';
$lang->cmd_advanced_mailer_smtp_security = 'SMTP security';
$lang->cmd_advanced_mailer_smtp_security_ssl = 'SSL';
$lang->cmd_advanced_mailer_smtp_security_tls = 'TLS (STARTTLS)';
$lang->cmd_advanced_mailer_smtp_security_none = 'None';
$lang->cmd_advanced_mailer_smtp_user = 'Username';
$lang->cmd_advanced_mailer_smtp_pass = 'Password';
$lang->cmd_advanced_mailer_api_domain = 'Domain';
$lang->cmd_advanced_mailer_api_token = 'API token';
$lang->cmd_advanced_mailer_api_type = 'API type';
$lang->cmd_advanced_mailer_api_type_free = 'Free account';
$lang->cmd_advanced_mailer_api_type_paid = 'Paid account';
$lang->cmd_advanced_mailer_api_user = 'Username';
$lang->cmd_advanced_mailer_api_pass = 'Password';
$lang->cmd_advanced_mailer_sender_identity = 'Sender Identity';
$lang->cmd_advanced_mailer_about_sender_identity = 'Sender identity will be applied to the webmaster\'s name and email address in the <a href="./index.php?module=admin&amp;act=dispMemberAdminConfig" target="_blank">member module</a> as well.';
$lang->cmd_advanced_mailer_sender_name = 'Sender\'s name';
$lang->cmd_advanced_mailer_sender_email = 'Sender\'s email';
$lang->cmd_advanced_mailer_reply_to = 'Reply-To email';
$lang->cmd_advanced_mailer_force_sender = 'Always Use This Email';
$lang->cmd_advanced_mailer_about_force_sender = 'Automatically change to the email address above if another module tries to send from a different address.';
$lang->cmd_advanced_mailer_about_force_sender_caution_line_1 = 'Caution: If you use SMTP with a free e-mail service, the sender\'s address must correspond to the SMTP login credentials.';
$lang->cmd_advanced_mailer_about_force_sender_caution_line_2 = 'The original sender\'s address will be used as Reply-To for your convenience.';
$lang->cmd_advanced_mailer_spf_dkim_setting = 'SPF/DKIM Setting Guide';
$lang->cmd_advanced_mailer_about_spf_dkim_setting = 'This is only applicable when sending emails from your own domain. Some APIs are not supported.';
$lang->cmd_advanced_mailer_not_applicable_because_sender_domain = 'Not applicable to the sender\'s domain.';
$lang->cmd_advanced_mailer_not_applicable_because_sending_method = 'Not applicable to the selected sending method.';
$lang->cmd_advanced_mailer_domain_count = '%d domains';
$lang->cmd_advanced_mailer_dns_hostname = 'DNS hostname';
$lang->cmd_advanced_mailer_txt_record = 'TXT record';
$lang->cmd_advanced_mailer_check = 'Check';
$lang->cmd_advanced_mailer_nothing_to_check = 'There is nothing to check.';
$lang->cmd_advanced_mailer_check_failure = 'Check failure.';
$lang->cmd_advanced_mailer_check_no_records = 'has no TXT records.';
$lang->cmd_advanced_mailer_check_result = 'has the following TXT records.';
$lang->cmd_advanced_mailer_other_info = 'Note';
$lang->cmd_advanced_mailer_other_info_mail_spf = 'In order to send mail to Korean recipients from your own server, please register a <a href="https://www.kisarbl.or.kr/" target="_blank">white domain</a> with KISA.';
$lang->cmd_advanced_mailer_other_info_ses_dkim = 'Please create three CNAME records according to the directions found in your AWS management console.';
$lang->cmd_advanced_mailer_other_info_mailgun_dkim = 'The DKIM hostname may be different from what is shown here.';
$lang->cmd_advanced_mailer_other_info_postmark_dkim = 'Please see the Sender Signatures page of your Postmark account for the exact DKIm hostname to use.';
$lang->cmd_advanced_mailer_other_info_woorimail_dkim = 'Please log into Woorimail to see your DKIM settings.';
$lang->cmd_advanced_mailer_ellipsis = '(see API for full value)';
$lang->cmd_advanced_mailer_test = 'Mail Test';
$lang->cmd_advanced_mailer_recipient_name = 'Recipient\'s name';
$lang->cmd_advanced_mailer_recipient_email = 'Recipient\'s email';
$lang->cmd_advanced_mailer_send = 'Send';
$lang->cmd_advanced_mailer_test_result = 'Test result';
$lang->cmd_advanced_mailer_exception_domains = 'Exception domains';
$lang->cmd_advanced_mailer_exception_disabled = 'Use default';
$lang->cmd_advanced_mailer_exception_domains_list = 'List of domains';
$lang->cmd_advanced_mailer_about_exception_domains_list = 'Domains should be separated by commas or line breaks. (Example: gmail.com, yahoo.com)';
$lang->cmd_advanced_mailer_about_exception_domains = 'When sending to domains listed here, the specified sending method will be used instead of the default.';
$lang->cmd_advanced_mailer_exception_group = 'Exception Group';
$lang->cmd_advanced_mailer_use_exceptions = 'Exception domains';
$lang->cmd_advanced_mailer_use_exceptions_yes = 'Test with exceptions as configured';
$lang->cmd_advanced_mailer_use_exceptions_no = 'Ignore exceptions and only test the default sending method';
$lang->msg_advanced_mailer_about_dummy = 'Dummy does not actually send any email. It only records them. Use this option for testing.';
$lang->msg_advanced_mailer_about_dummy_exceptions = 'Caution: if you have set up exception domains, email will be sent to those domains.';
$lang->msg_advanced_mailer_sending_method_is_invalid = 'Please select a valid sending method.';
$lang->msg_advanced_mailer_sending_method_is_not_configured = 'The selected sending method (%s) has not been fully configured. Please return to General Settings and finish configuring it.';
$lang->msg_advanced_mailer_smtp_host_is_invalid = 'Please enter a valid SMTP server name.';
$lang->msg_advanced_mailer_smtp_port_is_invalid = 'Please enter a valid SMTP port number.';
$lang->msg_advanced_mailer_smtp_security_is_invalid = 'Please select a valid SMTP security scheme.';
$lang->msg_advanced_mailer_username_is_empty = 'Please enter a username for the sending method you selected.';
$lang->msg_advanced_mailer_password_is_empty = 'Please enter a password for the sending method you selected.';
$lang->msg_advanced_mailer_aws_region_is_invalid = 'Please select a valid AWS Region.';
$lang->msg_advanced_mailer_aws_access_key_is_empty = 'Please enter a valid AWS Access Key.';
$lang->msg_advanced_mailer_aws_secret_key_is_empty = 'Please enter a valid AWS Secret Key.';
$lang->msg_advanced_mailer_domain_is_empty = 'Please enter a valid domain.';
$lang->msg_advanced_mailer_api_key_is_empty = 'Please enter a valid API Key.';
$lang->msg_advanced_mailer_sender_name_is_empty = 'Please enter the sender\'s name.';
$lang->msg_advanced_mailer_sender_email_is_empty = 'Please enter the sender\'s email address.';
$lang->msg_advanced_mailer_sender_email_is_invalid = 'The sender\'s email address is invalid.';
$lang->msg_advanced_mailer_reply_to_is_invalid = 'The Reply-To email address is invalid.';
$lang->msg_advanced_mailer_recipient_name_is_empty = 'Please enter the recipient\'s name.';
$lang->msg_advanced_mailer_recipient_email_is_empty = 'Please enter the recipient\'s email address.';
$lang->msg_advanced_mailer_recipient_email_is_invalid = 'The recipient\'s email address is invalid.';
$lang->msg_advanced_mailer_test_success = 'The test was successful. Please check your email.';
$lang->msg_advanced_mailer_google_account_security = 'Either your login credentials are incorrect, or the SMTP connection was blocked by Google account security settings.<br />Please <a href="https://support.google.com/mail/answer/14257" target="_blank">see here</a> for more information.';
$lang->msg_advanced_mailer_naver_smtp_disabled = 'Either your login credentials are incorrect, or POP3/SMTP is not enabled on your Naver account.';
$lang->msg_advanced_mailer_unknown_error = 'An unknown error occurred.';
$lang->msg_advanced_mailer_log_is_empty = 'There are no entries to display.';
$lang->cmd_advanced_mailer_status_sender = 'Sender';
$lang->cmd_advanced_mailer_status_recipient = 'Recipient';
$lang->cmd_advanced_mailer_status_subject = 'Subject';
$lang->cmd_advanced_mailer_status_sending_method = 'Method';
$lang->cmd_advanced_mailer_status_time = 'Time';
$lang->cmd_advanced_mailer_status = 'Status';
$lang->cmd_advanced_mailer_status_success = 'Success';
$lang->cmd_advanced_mailer_status_error = 'Error';
$lang->cmd_advanced_mailer_status_error_msg = 'Error message';
$lang->cmd_advanced_mailer_status_calling_script = 'Called from';
$lang->cmd_advanced_mailer_clear_log_condition_all = 'Everything';
$lang->cmd_advanced_mailer_clear_log_condition = 'Over %d days';
$lang->cmd_advanced_mailer_clear_log_button = 'Clear old logs';

View file

@ -0,0 +1,114 @@
<?php
$lang->cmd_advanced_mailer = '고급 메일 발송 모듈';
$lang->cmd_advanced_mailer_general_config = '기본 설정';
$lang->cmd_advanced_mailer_is_enabled = '모듈 사용';
$lang->cmd_advanced_mailer_is_enabled_yes = '사용';
$lang->cmd_advanced_mailer_is_enabled_no = '사용하지 않음';
$lang->cmd_advanced_mailer_logging = '발송 내역 기록';
$lang->cmd_advanced_mailer_log_sent_mail = '발송 내역';
$lang->cmd_advanced_mailer_log_errors = '에러 내역';
$lang->cmd_advanced_mailer_log_yes = '기록';
$lang->cmd_advanced_mailer_log_no = '기록하지 않음';
$lang->cmd_advanced_mailer_sending_method_config = '기본 발송 방법 설정';
$lang->cmd_advanced_mailer_about_sending_method_config = '반드시 모든 항목을 입력하시기 바랍니다.';
$lang->cmd_advanced_mailer_sending_method = '발송 방법';
$lang->cmd_advanced_mailer_about_sending_method = '받는이의 주소가 <a href="./index.php?module=admin&amp;act=dispAdvanced_mailerAdminExceptions" target="_blank">예외 도메인</a>에 해당하지 않을 경우 모두 이 방법으로 발송됩니다.';
$lang->cmd_advanced_mailer_sending_method_default = '기본 발송 방법';
$lang->cmd_advanced_mailer_sending_method_exceptions = '예외 발송 방법';
$lang->cmd_advanced_mailer_smtp_manual_entry = '직접 입력';
$lang->cmd_advanced_mailer_smtp_host = 'SMTP 서버';
$lang->cmd_advanced_mailer_smtp_port = 'SMTP 포트';
$lang->cmd_advanced_mailer_smtp_security = 'SMTP 보안';
$lang->cmd_advanced_mailer_smtp_security_ssl = 'SSL';
$lang->cmd_advanced_mailer_smtp_security_tls = 'TLS (STARTTLS)';
$lang->cmd_advanced_mailer_smtp_security_none = '사용하지 않음';
$lang->cmd_advanced_mailer_smtp_user = '아이디';
$lang->cmd_advanced_mailer_smtp_pass = '비밀번호';
$lang->cmd_advanced_mailer_api_domain = '도메인';
$lang->cmd_advanced_mailer_api_token = 'API 토큰';
$lang->cmd_advanced_mailer_api_type = 'API 구분';
$lang->cmd_advanced_mailer_api_type_free = '무료';
$lang->cmd_advanced_mailer_api_type_paid = '유료';
$lang->cmd_advanced_mailer_api_user = '아이디';
$lang->cmd_advanced_mailer_api_pass = '비밀번호';
$lang->cmd_advanced_mailer_sender_identity = '보낸이 설정';
$lang->cmd_advanced_mailer_about_sender_identity = '보낸이 설정은 <a href="./index.php?module=admin&amp;act=dispMemberAdminConfig" target="_blank">회원 모듈</a>의 웹마스터 이름 및 메일 주소에도 동일하게 적용됩니다.';
$lang->cmd_advanced_mailer_sender_name = '보낸이 이름';
$lang->cmd_advanced_mailer_sender_email = '보낸이 메일 주소';
$lang->cmd_advanced_mailer_reply_to = 'Reply-To 주소';
$lang->cmd_advanced_mailer_force_sender = '이 주소 외 사용 금지';
$lang->cmd_advanced_mailer_about_force_sender = '위에서 설정한 주소 외의 보낸이 주소를 사용할 경우 위에서 설정한 주소로 강제 변경합니다.';
$lang->cmd_advanced_mailer_about_force_sender_caution_line_1 = '포털 서비스의 SMTP를 사용할 경우 보낸이 메일 주소가 SMTP 로그인 정보와 반드시 일치해야 합니다.';
$lang->cmd_advanced_mailer_about_force_sender_caution_line_2 = '보낸이 주소를 강제 변경하더라도 원래 주소를 Reply-To로 지정하여 답장을 보내는 데는 지장이 없도록 합니다.';
$lang->cmd_advanced_mailer_spf_dkim_setting = 'SPF/DKIM 설정 안내';
$lang->cmd_advanced_mailer_about_spf_dkim_setting = '자신의 도메인에서 메일을 보내는 경우에만 해당됩니다. 일부 API는 지원하지 않거나 별도의 매뉴얼을 참고하셔야 합니다.';
$lang->cmd_advanced_mailer_not_applicable_because_sender_domain = '보내는 주소가 자신의 도메인이 아니므로 해당되지 않습니다.';
$lang->cmd_advanced_mailer_not_applicable_because_sending_method = '선택하신 발송 방법에는 해당되지 않습니다.';
$lang->cmd_advanced_mailer_domain_count = '도메인 %d개';
$lang->cmd_advanced_mailer_dns_hostname = 'DNS 호스트명';
$lang->cmd_advanced_mailer_txt_record = 'TXT 레코드 값';
$lang->cmd_advanced_mailer_check = '체크';
$lang->cmd_advanced_mailer_nothing_to_check = '체크할 것이 없습니다.';
$lang->cmd_advanced_mailer_check_failure = '체크에 실패했습니다.';
$lang->cmd_advanced_mailer_check_no_records = '호스트에는 TXT 레코드가 없습니다.';
$lang->cmd_advanced_mailer_check_result = '호스트의 TXT 레코드는 다음과 같습니다.';
$lang->cmd_advanced_mailer_other_info = '참고';
$lang->cmd_advanced_mailer_other_info_mail_spf = 'mail() 함수를 사용하려면 반드시 인터넷진흥원에 <a href="https://www.kisarbl.or.kr/" target="_blank">화이트 도메인</a> 등록을 하시기 바랍니다.';
$lang->cmd_advanced_mailer_other_info_ses_dkim = 'Amazon SES에서 DKIM을 사용하려면 관리 콘솔의 안내에 따라 3개의 CNAME 레코드를 생성해야 합니다.';
$lang->cmd_advanced_mailer_other_info_mailgun_dkim = 'DKIM 호스트명은 달라질 수 있습니다.';
$lang->cmd_advanced_mailer_other_info_postmark_dkim = '정확한 DKIM 호스트명은 Postmark 계정의 Sender Signatures 페이지를 참고하시기 바랍니다.';
$lang->cmd_advanced_mailer_other_info_woorimail_dkim = 'DKIM 설정은 우리메일에 로그인하여 확인하십시오.';
$lang->cmd_advanced_mailer_ellipsis = '(중략)';
$lang->cmd_advanced_mailer_test = '발송 테스트';
$lang->cmd_advanced_mailer_recipient_name = '받는이 이름';
$lang->cmd_advanced_mailer_recipient_email = '받는이 메일 주소';
$lang->cmd_advanced_mailer_send = '발송';
$lang->cmd_advanced_mailer_test_result = '테스트 결과';
$lang->cmd_advanced_mailer_exception_domains = '예외 도메인';
$lang->cmd_advanced_mailer_exception_disabled = '기본 발송 방법 사용';
$lang->cmd_advanced_mailer_exception_domains_list = '해당 도메인 목록';
$lang->cmd_advanced_mailer_about_exception_domains_list = '쉼표 또는 줄바꿈으로 구분하여 주십시오. (예: daum.net, hanmail.net)';
$lang->cmd_advanced_mailer_about_exception_domains = '목록에 나열된 도메인으로 메일을 보낼 때는 기본 발송 방법 대신 별도로 지정된 발송 방법을 사용합니다.';
$lang->cmd_advanced_mailer_exception_group = '예외 그룹';
$lang->cmd_advanced_mailer_use_exceptions = '예외 도메인 설정';
$lang->cmd_advanced_mailer_use_exceptions_yes = '예외 설정을 적용하여 테스트';
$lang->cmd_advanced_mailer_use_exceptions_no = '무시하고 기본 발송 방법만 테스트';
$lang->msg_advanced_mailer_about_dummy = '더미는 실제로 메일을 발송하지 않고 기록만 하는 옵션입니다. 테스트에 사용하십시오.';
$lang->msg_advanced_mailer_about_dummy_exceptions = '더미를 선택하더라도 예외 도메인을 지정한 경우 메일이 발송될 수 있으니 주의하십시오.';
$lang->msg_advanced_mailer_sending_method_is_invalid = '올바른 발송 방법을 선택해 주십시오.';
$lang->msg_advanced_mailer_sending_method_is_not_configured = '선택한 발송 방법(%s)이 완전히 설정되지 않았습니다. 기본 설정 페이지로 돌아가서 설정을 마쳐 주십시오.';
$lang->msg_advanced_mailer_smtp_host_is_invalid = '올바른 SMTP 서버 이름을 입력해 주십시오.';
$lang->msg_advanced_mailer_smtp_port_is_invalid = '올바른 SMTP 포트 번호를 입력해 주십시오.';
$lang->msg_advanced_mailer_smtp_security_is_invalid = '올바른 SMTP 보안 방식을 선택해 주십시오.';
$lang->msg_advanced_mailer_username_is_empty = '선택한 발송 방법에 필요한 아이디를 입력해 주십시오.';
$lang->msg_advanced_mailer_password_is_empty = '선택한 발송 방법에 필요한 비밀번호를 입력해 주십시오.';
$lang->msg_advanced_mailer_aws_region_is_invalid = '올바른 AWS Region을 선택해 주십시오.';
$lang->msg_advanced_mailer_aws_access_key_is_empty = 'AWS Access Key를 입력해 주십시오.';
$lang->msg_advanced_mailer_aws_secret_key_is_empty = 'AWS Secret Key를 입력해 주십시오.';
$lang->msg_advanced_mailer_domain_is_empty = '올바른 도메인을 입력해 주십시오.';
$lang->msg_advanced_mailer_api_key_is_empty = '올바른 API Key를 입력해 주십시오.';
$lang->msg_advanced_mailer_sender_name_is_empty = '보낸이 이름을 입력해 주십시오.';
$lang->msg_advanced_mailer_sender_email_is_empty = '보낸이 메일 주소를 입력해 주십시오.';
$lang->msg_advanced_mailer_sender_email_is_invalid = '보낸이 메일 주소가 올바른 메일 주소가 아닙니다.';
$lang->msg_advanced_mailer_reply_to_is_invalid = 'Reply-To 메일 주소가 올바른 메일 주소가 아닙니다.';
$lang->msg_advanced_mailer_recipient_name_is_empty = '받는이 이름을 입력해 주십시오.';
$lang->msg_advanced_mailer_recipient_email_is_empty = '받는이 메일 주소를 입력해 주십시오.';
$lang->msg_advanced_mailer_recipient_email_is_invalid = '받는이 메일 주소가 올바른 메일 주소가 아닙니다.';
$lang->msg_advanced_mailer_test_success = '테스트에 성공하였습니다. 메일을 확인해 보시기 바랍니다.';
$lang->msg_advanced_mailer_google_account_security = '아이디 또는 비밀번호가 틀렸거나, 구글 보안 설정 때문에 SMTP 접속이 차단되었습니다.<br />자세한 정보는 <a href="https://support.google.com/mail/answer/14257?hl=ko" target="_blank">여기</a>를 참고하시기 바랍니다.';
$lang->msg_advanced_mailer_naver_smtp_disabled = '아이디 또는 비밀번호가 틀렸거나, 네이버 계정 환경설정에서 POP3/SMTP를 사용하지 않도록 설정되어 있습니다.';
$lang->msg_advanced_mailer_unknown_error = '알 수 없는 오류가 발생하였습니다.';
$lang->msg_advanced_mailer_log_is_empty = '표시할 항목이 없습니다.';
$lang->cmd_advanced_mailer_status_sender = '보낸이';
$lang->cmd_advanced_mailer_status_recipient = '받는이';
$lang->cmd_advanced_mailer_status_subject = '제목';
$lang->cmd_advanced_mailer_status_sending_method = '발송 방법';
$lang->cmd_advanced_mailer_status_time = '발송 시간';
$lang->cmd_advanced_mailer_status = '상태';
$lang->cmd_advanced_mailer_status_success = '성공';
$lang->cmd_advanced_mailer_status_error = '에러';
$lang->cmd_advanced_mailer_status_error_msg = '에러 메시지';
$lang->cmd_advanced_mailer_status_calling_script = '호출 위치';
$lang->cmd_advanced_mailer_clear_log_condition_all = '모두';
$lang->cmd_advanced_mailer_clear_log_condition = '%d일 이상';
$lang->cmd_advanced_mailer_clear_log_button = '오래된 기록 삭제';

View file

@ -0,0 +1,11 @@
<query id="countLogByType" action="select">
<tables>
<table name="advanced_mailer_log" />
</tables>
<columns>
<column name="count(*)" alias="count" />
</columns>
<conditions>
<condition operation="equal" column="status" var="status" />
</conditions>
</query>

View file

@ -0,0 +1,9 @@
<query id="deleteLogs" action="delete">
<tables>
<table name="advanced_mailer_log" />
</tables>
<conditions>
<condition operation="equal" column="status" var="status" />
<condition operation="less" column="regdate" var="regdate" pipe="and" />
</conditions>
</query>

View file

@ -0,0 +1,17 @@
<query id="getLogByType" action="select">
<tables>
<table name="advanced_mailer_log" />
</tables>
<columns>
<column name="*" />
</columns>
<conditions>
<condition operation="equal" column="status" var="status" />
</conditions>
<navigation>
<index var="sort_index" default="mail_id" order="desc" />
<list_count var="list_count" default="20" />
<page_count var="page_count" default="10" />
<page var="page" default="1" />
</navigation>
</query>

View file

@ -0,0 +1,15 @@
<query id="insertLog" action="insert">
<tables>
<table name="advanced_mailer_log" />
</tables>
<columns>
<column name="mail_from" var="mail_from" notnull="notnull" />
<column name="mail_to" var="mail_to" notnull="notnull" />
<column name="subject" var="subject" notnull="notnull" />
<column name="calling_script" var="calling_script" notnull="notnull" />
<column name="sending_method" var="sending_method" notnull="notnull" />
<column name="regdate" var="regdate" notnull="notnull" default="curdate()" />
<column name="status" var="status" notnull="notnull" default="success" />
<column name="errors" var="errors" />
</columns>
</query>

View file

@ -0,0 +1,11 @@
<table name="advanced_mailer_log">
<column name="mail_id" type="number" size="11" notnull="notnull" primary_key="primary_key" auto_increment="auto_increment" />
<column name="mail_from" type="varchar" size="250" notnull="notnull" />
<column name="mail_to" type="text" notnull="notnull" />
<column name="subject" type="varchar" size="250" notnull="notnull" />
<column name="calling_script" type="varchar" size="250" notnull="notnull" />
<column name="sending_method" type="varchar" size="40" notnull="notnull" />
<column name="regdate" type="date" notnull="notnull" index="idx_regdate" />
<column name="status" type="varchar" size="40" notnull="notnull" index="idx_status" />
<column name="errors" type="bigtext" />
</table>

View file

@ -0,0 +1,13 @@
<div class="x_page-header">
<h1>{$lang->cmd_advanced_mailer}</h1>
</div>
<ul class="x_nav x_nav-tabs">
<li class="x_active"|cond="$act == 'dispAdvanced_mailerAdminConfig'"><a href="{getUrl('', 'module', 'admin', 'act', 'dispAdvanced_mailerAdminConfig')}">{$lang->cmd_advanced_mailer_general_config}</a></li>
<li class="x_active"|cond="$act == 'dispAdvanced_mailerAdminExceptions'"><a href="{getUrl('', 'module', 'admin', 'act', 'dispAdvanced_mailerAdminExceptions')}">{$lang->cmd_advanced_mailer_exception_domains}</a></li>
<li class="x_active"|cond="$act == 'dispAdvanced_mailerAdminSpfDkim'"><a href="{getUrl('', 'module', 'admin', 'act', 'dispAdvanced_mailerAdminSpfDkim')}">{$lang->cmd_advanced_mailer_spf_dkim_setting}</a></li>
<li class="x_active"|cond="$act == 'dispAdvanced_mailerAdminTestConfig'"><a href="{getUrl('', 'module', 'admin', 'act', 'dispAdvanced_mailerAdminTestConfig')}">{$lang->cmd_advanced_mailer_test}</a></li>
<li class="x_active"|cond="$act == 'dispAdvanced_mailerAdminSentMail'"><a href="{getUrl('', 'module', 'admin', 'act', 'dispAdvanced_mailerAdminSentMail')}">{$lang->cmd_advanced_mailer_log_sent_mail}</a></li>
<li class="x_active"|cond="$act == 'dispAdvanced_mailerAdminErrors'"><a href="{getUrl('', 'module', 'admin', 'act', 'dispAdvanced_mailerAdminErrors')}">{$lang->cmd_advanced_mailer_log_errors}</a></li>
</ul>

View file

@ -0,0 +1,230 @@
<include target="./common.html" />
<load target="css/config.css" />
<load target="js/config.js" />
<form class="x_form-horizontal" action="./" method="post" id="advanced_mailer">
<input type="hidden" name="module" value="advanced_mailer" />
<input type="hidden" name="act" value="procAdvanced_mailerAdminInsertConfig" />
<input type="hidden" name="success_return_url" value="{getRequestUriByServerEnviroment()}" />
<div cond="$XE_VALIDATOR_MESSAGE" class="message {$XE_VALIDATOR_MESSAGE_TYPE}">
<p>{$XE_VALIDATOR_MESSAGE}</p>
</div>
<section class="section">
<h2 style="padding-top:12px">{$lang->cmd_advanced_mailer_sending_method_config}</h2>
<div class="advanced_mailer_description">
※ {$lang->cmd_advanced_mailer_about_sending_method}
</div>
<div class="x_control-group show-always">
<label class="x_control-label" for="advanced_mailer_sending_method">{$lang->cmd_advanced_mailer_sending_method_default}</label>
<div class="x_controls">
<select name="sending_method" id="advanced_mailer_sending_method">
<!--@foreach($sending_methods as $driver_name => $driver_definition)-->
<option value="{$driver_name}" selected="selected"|cond="$sending_method === $driver_name">{$driver_definition['name']}</option>
<!--@end-->
</select>
</div>
</div>
<script type="text/javascript">
var advanced_mailer_sending_methods = {json_encode($sending_methods)};
</script>
<div class="x_control-group hidden-by-default show-for-dummy">
<label class="x_control-label"></label>
<div class="x_controls">
<p class="x_help-block">{$lang->msg_advanced_mailer_about_dummy}<br />{$lang->msg_advanced_mailer_about_dummy_exceptions}</p>
</div>
</div>
<!--@foreach($sending_methods as $driver_name => $driver_definition)-->
<!--@foreach($driver_definition['required'] as $conf_name)-->
{@ $conf_value = escape(config("mail.$driver_name.$conf_name"))}
<!--@if($conf_name === 'smtp_host')-->
<div class="x_control-group hidden-by-default show-for-{$driver_name}">
<label class="x_control-label" for="advanced_mailer_{$driver_name}_smtp_host">{$lang->cmd_advanced_mailer_smtp_host}</label>
<div class="x_controls">
<input type="text" name="{$driver_name}_smtp_host" id="advanced_mailer_{$driver_name}_smtp_host" value="{$conf_value}" />
<select id="advanced_mailer_{$driver_name}_manual_entry">
<option value="">{$lang->cmd_advanced_mailer_smtp_manual_entry}</option>
<option value="gmail">Gmail</option>
<option value="hanmail">Hanmail</option>
<option value="naver">Naver</option>
<option value="worksmobile">Works Mobile</option>
<option value="outlook">Outlook.com</option>
<option value="yahoo">Yahoo</option>
</select>
</div>
</div>
<!--@end-->
<!--@if($conf_name === 'smtp_port')-->
<div class="x_control-group hidden-by-default show-for-{$driver_name}">
<label class="x_control-label" for="advanced_mailer_{$driver_name}_smtp_port">{$lang->cmd_advanced_mailer_smtp_port}</label>
<div class="x_controls">
<input type="text" name="{$driver_name}_smtp_port" id="advanced_mailer_{$driver_name}_smtp_port" value="{$conf_value}" />
</div>
</div>
<!--@end-->
<!--@if($conf_name === 'smtp_security')-->
<div class="x_control-group hidden-by-default show-for-{$driver_name}">
<label class="x_control-label">{$lang->cmd_advanced_mailer_smtp_security}</label>
<div class="x_controls">
<label class="x_inline" for="advanced_mailer_{$driver_name}_security_none"><input type="radio" name="{$driver_name}_smtp_security" id="advanced_mailer_{$driver_name}_security_none" value="none" checked="checked"|cond="!in_array($conf_value, array('ssl', 'tls'))" /> {$lang->cmd_advanced_mailer_smtp_security_none}</label>
<label class="x_inline" for="advanced_mailer_{$driver_name}_security_ssl"><input type="radio" name="{$driver_name}_smtp_security" id="advanced_mailer_{$driver_name}_security_ssl" value="ssl" checked="checked"|cond="$conf_value === 'ssl'" /> {$lang->cmd_advanced_mailer_smtp_security_ssl}</label>
<label class="x_inline" for="advanced_mailer_{$driver_name}_security_tls"><input type="radio" name="{$driver_name}_smtp_security" id="advanced_mailer_{$driver_name}_security_tls" value="tls" checked="checked"|cond="$conf_value === 'tls'" /> {$lang->cmd_advanced_mailer_smtp_security_tls}</label>
</div>
</div>
<!--@end-->
<!--@if($conf_name === 'smtp_user')-->
<div class="x_control-group hidden-by-default show-for-{$driver_name}">
<label class="x_control-label" for="advanced_mailer_{$driver_name}_smtp_user">{$lang->cmd_advanced_mailer_smtp_user}</label>
<div class="x_controls">
<input type="text" name="{$driver_name}_smtp_user" id="advanced_mailer_{$driver_name}_smtp_user" value="{$conf_value}" />
</div>
</div>
<!--@end-->
<!--@if($conf_name === 'smtp_pass')-->
<div class="x_control-group hidden-by-default show-for-{$driver_name}">
<label class="x_control-label" for="advanced_mailer_smtp_pass">{$lang->cmd_advanced_mailer_smtp_pass}</label>
<div class="x_controls">
<input type="smtp_pass" name="{$driver_name}_smtp_pass" id="advanced_mailer_{$driver_name}_smtp_pass" value="{$conf_value}" />
</div>
</div>
<!--@end-->
<!--@if($conf_name === 'api_type')-->
<div class="x_control-group hidden-by-default show-for-{$driver_name}">
<label class="x_control-label" for="advanced_mailer_{$driver_name}_api_type">{$lang->cmd_advanced_mailer_api_type}</label>
<div class="x_controls">
<select id="advanced_mailer_{$driver_name}_api_type" name="{$driver_name}_api_type">
<!--@foreach($driver_definition['api_types'] as $api_type)-->
<option value="{$api_type}" selected="selected"|cond="$api_type === $conf_value">{$api_type}</option>
<!--@end-->
</select>
</div>
</div>
<!--@end-->
<!--@if($conf_name === 'api_domain')-->
<div class="x_control-group hidden-by-default show-for-{$driver_name}">
<label class="x_control-label" for="advanced_mailer_{$driver_name}_api_domain">{$lang->cmd_advanced_mailer_api_domain}</label>
<div class="x_controls">
<input type="text" name="{$driver_name}_api_domain" id="advanced_mailer_{$driver_name}_api_domain" value="{$conf_value}" />
</div>
</div>
<!--@end-->
<!--@if($conf_name === 'api_token')-->
<div class="x_control-group hidden-by-default show-for-{$driver_name}">
<label class="x_control-label" for="advanced_mailer_{$driver_name}_api_token">{$lang->cmd_advanced_mailer_api_token}</label>
<div class="x_controls full-width">
<input type="text" name="{$driver_name}_api_token" id="advanced_mailer_{$driver_name}_api_token" value="{$conf_value}" />
</div>
</div>
<!--@end-->
<!--@if($conf_name === 'api_user')-->
<div class="x_control-group hidden-by-default show-for-{$driver_name}">
<label class="x_control-label" for="advanced_mailer_{$driver_name}_api_user">{$lang->cmd_advanced_mailer_api_user}</label>
<div class="x_controls">
<input type="text" name="{$driver_name}_api_user" id="advanced_mailer_{$driver_name}_api_user" value="{$conf_value}" />
</div>
</div>
<!--@end-->
<!--@if($conf_name === 'api_pass')-->
<div class="x_control-group hidden-by-default show-for-{$driver_name}">
<label class="x_control-label" for="advanced_mailer_{$driver_name}_api_pass">{$lang->cmd_advanced_mailer_api_pass}</label>
<div class="x_controls full-width">
<input type="password" name="{$driver_name}_api_pass" id="advanced_mailer_{$driver_name}_api_pass" value="{$conf_value}" />
</div>
</div>
<!--@end-->
<!--@end-->
<!--@end-->
</section>
<section class="section">
<h2 style="padding-top:12px">{$lang->cmd_advanced_mailer_sender_identity}</h2>
<div class="advanced_mailer_description">
※ {$lang->cmd_advanced_mailer_about_sender_identity}
</div>
<div class="x_control-group">
<label class="x_control-label" for="advanced_mailer_sender_name">{$lang->cmd_advanced_mailer_sender_name}</label>
<div class="x_controls">
<input type="text" name="sender_name" id="advanced_mailer_sender_name" value="{$webmaster_name}" />
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="advanced_mailer_sender_email">{$lang->cmd_advanced_mailer_sender_email}</label>
<div class="x_controls">
<input type="text" name="sender_email" id="advanced_mailer_sender_email" value="{$webmaster_email}" />
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="advanced_mailer_reply_to">{$lang->cmd_advanced_mailer_reply_to}</label>
<div class="x_controls">
<input type="text" name="reply_to" id="advanced_mailer_reply_to" value="{$advanced_mailer_config->reply_to}" />
</div>
</div>
<div class="x_control-group">
<label class="x_control-label">{$lang->cmd_advanced_mailer_force_sender}</label>
<div class="x_controls">
<label for="advanced_mailer_force_sender">
<input type="checkbox" name="force_sender" id="advanced_mailer_force_sender" value="Y" checked="checked"|cond="toBool($advanced_mailer_config->force_sender)" />
{$lang->cmd_advanced_mailer_about_force_sender}
</label>
<p>※ {$lang->cmd_advanced_mailer_about_force_sender_caution_line_1}<br />※ {$lang->cmd_advanced_mailer_about_force_sender_caution_line_2}</p>
</div>
</div>
</section>
<section class="section">
<h2 style="padding-top:12px">{$lang->cmd_advanced_mailer_logging}</h2>
<div class="x_control-group">
<label class="x_control-label" for="advanced_mailer_log_sent_mail">{$lang->cmd_advanced_mailer_log_sent_mail}</label>
<div class="x_controls">
<select name="log_sent_mail" id="advanced_mailer_log_sent_mail">
<option value="Y" selected="selected"|cond="toBool($advanced_mailer_config->log_sent_mail)" />{$lang->cmd_advanced_mailer_log_yes}</option>
<option value="N" selected="selected"|cond="!toBool($advanced_mailer_config->log_sent_mail)" />{$lang->cmd_advanced_mailer_log_no}</option>
</select>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label">{$lang->cmd_advanced_mailer_log_errors}</label>
<div class="x_controls">
<select name="log_errors" id="advanced_mailer_log_errors">
<option value="Y" selected="selected"|cond="toBool($advanced_mailer_config->log_errors)" />{$lang->cmd_advanced_mailer_log_yes}</option>
<option value="N" selected="selected"|cond="!toBool($advanced_mailer_config->log_errors)" />{$lang->cmd_advanced_mailer_log_no}</option>
</select>
</div>
</div>
</section>
<div class="btnArea x_clearfix">
<button type="submit" class="x_btn x_btn-primary x_pull-right">{$lang->cmd_registration}</button>
</div>
</form>

View file

@ -0,0 +1,52 @@
#advanced_mailer_test_send {
padding: 3px 10px;
}
#advanced_mailer_test_result {
font-family: Consolas, monospace;
padding: 5px 0;
}
section {
margin-bottom: 10px !important;
}
input[type=password] {
font-family: "Segoe UI", Arial, sans-serif !important;
}
h2 {
padding-left: 10px;
padding-bottom: 2px;
font-size: 16px !important;
}
div.advanced_mailer_description {
margin-bottom: 10px;
margin-left: 10px;
}
div.hidden-by-default {
display: none;
}
div.full-width input {
width: 90% !important;
}
div.margin-top {
margin-top: 5px;
}
span.sender_info {
display: inline-block;
margin-top: 12px;
margin-left: 24px;
font-family: Consolas, monospace;
}
textarea.exception-domains {
width: 90% !important;
height: 80px !important;
}

View file

@ -0,0 +1,31 @@
div.advanced_mailer_description {
margin-bottom: 10px;
margin-left: 10px;
}
div.margin-top {
margin-top: 5px;
}
div.x_modal-body .monospace {
font-family: Consolas, monospace;
word-wrap: break-word;
word-break: break-word;
}
#spf_dkim_setting div.spf_dkim_item {
padding: 5px 0;
}
#spf_dkim_setting div.spf_dkim_separator {
border-top: 1px dotted #ddd;
margin: 8px 0;
}
#spf_dkim_setting span.label {
display: inline-block;
min-width: 94px;
}
#spf_dkim_setting span.monospace {
font-family: Consolas, monospace;
display: inline-block;
}

View file

@ -0,0 +1,4 @@
div.mail-log-errors {
display: none;
}

View file

@ -0,0 +1,67 @@
<include target="./common.html" />
<load target="css/config.css" />
<form class="x_form-horizontal" action="./" method="post" id="advanced_mailer">
<input type="hidden" name="module" value="advanced_mailer" />
<input type="hidden" name="act" value="procAdvanced_mailerAdminInsertExceptions" />
<input type="hidden" name="success_return_url" value="{getRequestUriByServerEnviroment()}" />
<div cond="$XE_VALIDATOR_MESSAGE" class="message {$XE_VALIDATOR_MESSAGE_TYPE}">
<p>{$XE_VALIDATOR_MESSAGE}</p>
</div>
<section class="section">
<div class="x_control-group">
<label class="x_control-label">{$lang->cmd_advanced_mailer_sending_method_default}</label>
<div class="x_controls margin-top">
{$sending_methods[$sending_method]['name']}
<!--@if($sending_method === 'woorimail')-->
<!--@if(config('mail.woorimail.api_type') === 'free')-->
({$lang->cmd_advanced_mailer_api_type_free})
<!--@else-->
({$lang->cmd_advanced_mailer_api_type_paid})
<!--@end-->
<!--@end-->
</div>
</div>
</section>
<!--@for($i = 1; $i <= 3; $i++)-->
<section class="section">
<h2 style="padding-top:12px">{$lang->cmd_advanced_mailer_exception_group} {$i}</h2>
<div class="x_control-group">
<label class="x_control-label" for="advanced_mailer_exception_{$i}_method">{$lang->cmd_advanced_mailer_sending_method}</label>
<div class="x_controls">
<select name="exception_{$i}_method" id="advanced_mailer_exception_{$i}_method">
<option value="default">{$lang->cmd_advanced_mailer_exception_disabled}</option>
<!--@foreach($sending_methods as $driver_name => $driver_definition)-->
<option value="{$driver_name}" selected="selected"|cond="$advanced_mailer_config->exceptions[$i]['method'] === $driver_name">{$driver_definition['name']}</option>
<!--@end-->
</select>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="advanced_mailer_exception_{$i}_domains">{$lang->cmd_advanced_mailer_exception_domains_list}</label>
<div class="x_controls">
<textarea name="exception_{$i}_domains" id="advanced_mailer_exception_{$i}_domains" class="exception-domains">{implode(', ', $advanced_mailer_config->exceptions[$i]['domains'])}</textarea>
<p class="x_help-block">{$lang->cmd_advanced_mailer_about_exception_domains_list}</p>
</div>
</div>
</section>
<!--@end-->
<div style="margin-top:32px">
※ {$lang->cmd_advanced_mailer_about_exception_domains}
</div>
<div class="btnArea x_clearfix">
<button type="submit" class="x_btn x_btn-primary x_pull-right">{$lang->cmd_registration}</button>
</div>
</form>

View file

@ -0,0 +1,106 @@
(function($) {
$(function() {
$("#advanced_mailer_sending_method").on("change", function() {
var sending_method = $(this).val();
$("div.x_control-group.hidden-by-default").not(".show-always").each(function() {
if ($(this).hasClass("show-for-" + sending_method)) {
$(this).show();
} else {
$(this).hide();
}
});
var reply_to = $("#advanced_mailer_reply_to").parents("div.x_control-group");
if (sending_method === "woorimail") {
reply_to.hide();
} else {
reply_to.show();
}
}).triggerHandler("change");
$("#advanced_mailer_smtp_manual_entry").on("change", function() {
var auto_fill = $(this).val();
if (auto_fill === 'gmail') {
$("#advanced_mailer_smtp_host").val('smtp.gmail.com');
$("#advanced_mailer_smtp_port").val('465');
$("#advanced_mailer_smtp_security_ssl").prop("checked", true).parent().addClass("checked");
$("#advanced_mailer_smtp_security_tls").parent().removeClass("checked");
$("#advanced_mailer_smtp_security_none").parent().removeClass("checked");
$("#advanced_mailer_force_sender").prop("checked", true).parent().addClass("checked");
}
if (auto_fill === 'hanmail') {
$("#advanced_mailer_smtp_host").val('smtp.daum.net');
$("#advanced_mailer_smtp_port").val('465');
$("#advanced_mailer_smtp_security_ssl").prop("checked", true).parent().addClass("checked");
$("#advanced_mailer_smtp_security_tls").parent().removeClass("checked");
$("#advanced_mailer_smtp_security_none").parent().removeClass("checked");
$("#advanced_mailer_force_sender").prop("checked", true).parent().addClass("checked");
}
if (auto_fill === 'naver') {
$("#advanced_mailer_smtp_host").val('smtp.naver.com');
$("#advanced_mailer_smtp_port").val('587');
$("#advanced_mailer_smtp_security_tls").prop("checked", true).parent().addClass("checked");
$("#advanced_mailer_smtp_security_ssl").parent().removeClass("checked");
$("#advanced_mailer_smtp_security_none").parent().removeClass("checked");
$("#advanced_mailer_force_sender").prop("checked", true).parent().addClass("checked");
}
if (auto_fill === 'worksmobile') {
$("#advanced_mailer_smtp_host").val('smtp.worksmobile.com');
$("#advanced_mailer_smtp_port").val('587');
$("#advanced_mailer_smtp_security_tls").prop("checked", true).parent().addClass("checked");
$("#advanced_mailer_smtp_security_ssl").parent().removeClass("checked");
$("#advanced_mailer_smtp_security_none").parent().removeClass("checked");
$("#advanced_mailer_force_sender").prop("checked", true).parent().addClass("checked");
}
if (auto_fill === 'outlook') {
$("#advanced_mailer_smtp_host").val('smtp-mail.outlook.com');
$("#advanced_mailer_smtp_port").val('587');
$("#advanced_mailer_smtp_security_tls").prop("checked", true).parent().addClass("checked");
$("#advanced_mailer_smtp_security_ssl").parent().removeClass("checked");
$("#advanced_mailer_smtp_security_none").parent().removeClass("checked");
$("#advanced_mailer_force_sender").prop("checked", true).parent().addClass("checked");
}
if (auto_fill === 'yahoo') {
$("#advanced_mailer_smtp_host").val('smtp.mail.yahoo.com');
$("#advanced_mailer_smtp_port").val('465');
$("#advanced_mailer_smtp_security_ssl").prop("checked", true).parent().addClass("checked");
$("#advanced_mailer_smtp_security_tls").parent().removeClass("checked");
$("#advanced_mailer_smtp_security_none").parent().removeClass("checked");
$("#advanced_mailer_force_sender").prop("checked", true).parent().addClass("checked");
}
});
$("#advanced_mailer_woorimail_account_type_free,#advanced_mailer_woorimail_account_type_paid").on("change", function() {
if ($("#advanced_mailer_woorimail_account_type_paid").is(":checked")) {
$("#advanced_mailer_reply_to").attr("disabled", "disabled");
} else {
$("#advanced_mailer_reply_to").removeAttr("disabled");
}
}).triggerHandler("change");
$("#advanced_mailer_test_send").click(function(event) {
event.preventDefault();
$("#advanced_mailer_test_result").text("");
$(this).attr("disabled", "disabled");
var ajax_data = {
recipient_name: $("#advanced_mailer_recipient_name").val(),
recipient_email: $("#advanced_mailer_recipient_email").val(),
};
$.exec_json(
"advanced_mailer.procAdvanced_mailerAdminTestSend", ajax_data,
function(response) {
$("#advanced_mailer_test_result").html(response.test_result);
$("#advanced_mailer_test_send").removeAttr("disabled");
},
function(response) {
$("#advanced_mailer_test_result").text("AJAX Error");
$("#advanced_mailer_test_send").removeAttr("disabled");
}
);
});
});
} (jQuery));

View file

@ -0,0 +1,43 @@
(function($) {
$(function() {
$("#advanced_mailer_check_spf,#advanced_mailer_check_dkim").click(function(event) {
event.preventDefault();
var check_type = $(this).attr("id").match(/_spf$/) ? "spf" : "dkim";
var check_hostname = $(this).siblings("span.monospace").text();
if (!check_hostname) {
alert($("#spf_dkim_setting").data("nothing-to-check"));
}
$(this).attr("disabled", "disabled");
$.exec_json(
"advanced_mailer.procAdvanced_mailerAdminCheckDNSRecord",
{ hostname: check_hostname, record_type: "TXT" },
function(response) {
if (response.record_content === false) {
alert($("#spf_dkim_setting").data("check-failure"));
}
else if (response.record_content === "") {
alert('<span class="monospace">' + check_hostname + "</span> " +
$("#spf_dkim_setting").data("check-no-records"));
$(".x_modal._common._small").removeClass("_small");
}
else {
alert('<span class="monospace">' + check_hostname + "</span> " +
$("#spf_dkim_setting").data("check-result") + "<br /><br />" +
'<div class="monospace">' + response.record_content.replace("\n", "<br />") + "</div>");
$(".x_modal._common._small").removeClass("_small");
}
$("#advanced_mailer_check_" + check_type).removeAttr("disabled");
},
function(response) {
alert($("#spf_dkim_setting").data("check-failure"));
$("#advanced_mailer_check_" + check_type).removeAttr("disabled");
}
);
});
});
} (jQuery));

View file

@ -0,0 +1,15 @@
(function($) {
$(function() {
$("a.show-errors").click(function(event) {
event.preventDefault();
var error_msg = $(this).siblings("div.mail-log-errors").html();
alert(error_msg);
$(".x_modal._common._small").removeClass("_small");
});
});
} (jQuery));

View file

@ -0,0 +1,127 @@
<include target="./common.html" />
<load target="css/spf_dkim.css" />
<load target="js/spf_dkim.js" />
<div id="spf_dkim_setting" class="x_form-horizontal"
data-nothing-to-check="{$lang->cmd_advanced_mailer_nothing_to_check}"
data-check-no-records="{$lang->cmd_advanced_mailer_check_no_records}"
data-check-failure="{$lang->cmd_advanced_mailer_check_failure}"
data-check-result="{$lang->cmd_advanced_mailer_check_result}">
<div class="advanced_mailer_description">
※ {$lang->cmd_advanced_mailer_about_spf_dkim_setting}
</div>
<div class="x_control-group">
<label class="x_control-label">{$lang->cmd_advanced_mailer_sending_method_default}</label>
<div class="x_controls margin-top">
{$sending_methods[$sending_method]['name']}
<!--@if($sending_method === 'woorimail')-->
<!--@if(config('mail.woorimail.api_type') === 'free')-->
({$lang->cmd_advanced_mailer_api_type_free})
<!--@else-->
({$lang->cmd_advanced_mailer_api_type_paid})
<!--@end-->
<!--@end-->
</div>
</div>
<div class="x_control-group" cond="count($used_methods) > 1">
<label class="x_control-label">{$lang->cmd_advanced_mailer_sending_method_exceptions}</label>
<div class="x_controls">
<!--@foreach($advanced_mailer_config->exceptions as $exception)-->
<!--@if(in_array($exception['method'], $used_methods))-->
<div class="spf_dkim_item">
{$sending_methods[$exception['method']]['name']}
<!--@if($exception['method'] === 'woorimail')-->
<!--@if(config('mail.woorimail.api_type') === 'free')-->
({$lang->cmd_advanced_mailer_api_type_free})
<!--@else-->
({$lang->cmd_advanced_mailer_api_type_paid})
<!--@end-->
<!--@end-->
&mdash; {sprintf($lang->cmd_advanced_mailer_domain_count, count($exception['domains']))}
</div>
<!--@end-->
<!--@end-->
</div>
</div>
<div class="x_control-group">
<label class="x_control-label">{$lang->cmd_advanced_mailer_sender_email}</label>
<div class="x_controls margin-top">{$advanced_mailer_config->sender_email}</div>
</div>
{@ $ignore_domains = '/^(g(oogle)?mail\.com|(daum|hanmail2?)\.net|(naver|outlook|hotmail|yahoo)\.com|(hotmail|yahoo)\.co\.kr)$/i'}
<div class="x_control-group">
<label class="x_control-label">SPF</label>
<div class="x_controls">
<!--@if(preg_match($ignore_domains, $sending_domain))-->
<div class="spf_dkim_item">
{$lang->cmd_advanced_mailer_not_applicable_because_sender_domain}
</div>
<!--@elseif(!count($used_methods_with_usable_spf))-->
<div class="spf_dkim_item">
{$lang->cmd_advanced_mailer_not_applicable_because_sending_method}
</div>
<!--@else-->
<div class="spf_dkim_item">
<span class="label">{$lang->cmd_advanced_mailer_dns_hostname}</span>
<span class="monospace">{$sending_domain}</span> &nbsp;
<a href="#" id="advanced_mailer_check_spf">{$lang->cmd_advanced_mailer_check}</a>
</div>
<div class="spf_dkim_item">
<span class="label">{$lang->cmd_advanced_mailer_txt_record}</span>
<span class="monospace">v=spf1 a mx {implode(' ', $used_methods_with_usable_spf)} ~all</span>
</div>
{@ $other_infos = array()}
<!--@foreach($used_methods_with_usable_spf as $method => $spf)-->
{@ $other_info = Context::getLang('cmd_advanced_mailer_other_info_' . $method . '_spf')}
{@ if(strncmp('cmd_', $other_info, 4)) $other_infos[] = $other_info}
<!--@end-->
<div class="spf_dkim_item" cond="count($other_infos)">
<!--@foreach($other_infos as $other_info)-->
<span class="label">{$lang->cmd_advanced_mailer_other_info}</span>
<span>{$other_info}</span><br />
<!--@end-->
</div>
<!--@end-->
</div>
</div>
<div class="x_control-group">
<label class="x_control-label">DKIM</label>
<div class="x_controls">
<!--@if(preg_match($ignore_domains, $sending_domain))-->
<div class="spf_dkim_item">
{$lang->cmd_advanced_mailer_not_applicable_because_sender_domain}
</div>
<!--@elseif(!count($used_methods_with_usable_dkim))-->
<div class="spf_dkim_item">
{$lang->cmd_advanced_mailer_not_applicable_because_sending_method}
</div>
<!--@else-->
<!--@foreach($used_methods_with_usable_dkim as $method => $dkim)-->
<div class="spf_dkim_item">
<span class="label">{$lang->cmd_advanced_mailer_dns_hostname}</span>
<span class="monospace">{$dkim}.{$sending_domain}</span> &nbsp;
<a href="#" id="advanced_mailer_check_spf">{$lang->cmd_advanced_mailer_check}</a>
</div>
<div class="spf_dkim_item">
<span class="label">{$lang->cmd_advanced_mailer_txt_record}</span>
<span class="monospace">v=DKIM1; k=rsa; p=MIGfMA...{$lang->cmd_advanced_mailer_ellipsis}...QAB;</span>
</div>
{@ $other_info = Context::getLang('cmd_advanced_mailer_other_info_' . $method . '_dkim')}
{@ if(!strncmp('cmd_', $other_info, 4)) $other_info = false}
<div class="spf_dkim_item" cond="$other_info">
<span class="label">{$lang->cmd_advanced_mailer_other_info}</span>
<span>{$other_info}</span><br />
</div>
<div class="spf_dkim_separator"></div>
<!--@end-->
<!--@end-->
</div>
</div>
</div>

View file

@ -0,0 +1,45 @@
<include target="./common.html" />
<load target="css/config.css" />
<load target="js/config.js" />
<form class="x_form-horizontal" action="./" method="post" id="advanced_mailer">
<input type="hidden" name="module" value="advanced_mailer" />
<input type="hidden" name="act" value="procAdvanced_mailerAdminTestConfig" />
<input type="hidden" name="success_return_url" value="{getRequestUriByServerEnviroment()}" />
<div cond="$XE_VALIDATOR_MESSAGE" class="message {$XE_VALIDATOR_MESSAGE_TYPE}">
<p>{$XE_VALIDATOR_MESSAGE}</p>
</div>
<section class="section">
<h2>{$lang->cmd_advanced_mailer_test}</h2>
<div class="x_control-group">
<label class="x_control-label" for="advanced_mailer_recipient_name">{$lang->cmd_advanced_mailer_recipient_name}</label>
<div class="x_controls">
<input type="text" id="advanced_mailer_recipient_name" value="{Context::get('logged_info')->nick_name}" />
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="advanced_mailer_recipient_email">{$lang->cmd_advanced_mailer_recipient_email}</label>
<div class="x_controls">
<input type="text" id="advanced_mailer_recipient_email" value="{Context::get('logged_info')->email_address}" />
</div>
</div>
<div class="x_control-group">
<label class="x_control-label">{$lang->cmd_advanced_mailer_test_result}</label>
<div class="x_controls">
<div id="advanced_mailer_test_result"></div>
</div>
</div>
</section>
<div class="btnArea x_clearfix">
<button id="advanced_mailer_test_send" type="submit" class="x_btn x_btn-primary x_pull-right">{$lang->cmd_advanced_mailer_send}</button>
</div>
</form>

View file

@ -0,0 +1,85 @@
<include target="./common.html" />
<load target="css/view_log.css" />
<load target="js/view_log.js" />
<table id="advanced_mailer_log" class="x_table x_table-striped x_table-hover">
<caption>
<strong>Total: {number_format($total_count)}, Page: {number_format($page)}/{number_format($total_page)}</strong>
</caption>
<thead>
<tr>
<th scope="col" class="nowr">{$lang->cmd_advanced_mailer_status_sender}</th>
<th scope="col" class="nowr">{$lang->cmd_advanced_mailer_status_recipient}</th>
<th scope="col" class="nowr">{$lang->cmd_advanced_mailer_status_subject}</th>
<th scope="col" class="nowr">{$lang->cmd_advanced_mailer_status_sending_method}</th>
<th scope="col" class="nowr">{$lang->cmd_advanced_mailer_status_time}</th>
<th scope="col" class="nowr">{$lang->cmd_advanced_mailer_status}</th>
</tr>
</thead>
<tbody>
<tr loop="$advanced_mailer_log => $mail_id, $val">
<td class="nowr">
<!--@foreach($val->mail_from as $no => $mail_from)-->
<span title="{htmlspecialchars($mail_from[1])}">{htmlspecialchars($mail_from[0])}</span><br />
<!--@end-->
</td>
<td class="nowr">
<!--@foreach($val->mail_to as $no => $mail_to)-->
<span class="hidden"|cond="$no > 0" title="{htmlspecialchars($mail_to[1])}">{htmlspecialchars($mail_to[0])}</span>
<span class="show-hidden-recipients" cond="$no == 0 && count($val->mail_to) > 1">+{count($val->mail_to) - 1}</span>
<br />
<!--@end-->
</td>
<td class="nowr">{htmlspecialchars($val->subject)}</td>
<td class="nowr">
{@ if($val->sending_method === 'mail') $val->sending_method = 'mailfunction'}
{strval(isset($sending_methods[$val->sending_method]['name']) ? $sending_methods[$val->sending_method]['name'] : $val->sending_method)}
</td>
<td class="nowr">{(zdate($val->regdate, "Y-m-d\nH:i:s"))}</td>
<td class="nowr">
<!--@if($val->status === 'success')-->
{$lang->cmd_advanced_mailer_status_success}
<!--@else-->
<a href="javascript:void(0)" class="show-errors">{$lang->cmd_advanced_mailer_status_error}</a>
<div class="mail-log-errors">
<strong>{$lang->cmd_advanced_mailer_status_error_msg}:</strong><br />
{nl2br(htmlspecialchars(trim($val->errors)))}<br /><br />
<strong>{$lang->cmd_advanced_mailer_status_calling_script}:</strong><br />
{htmlspecialchars($val->calling_script)}
</div>
<!--@end-->
</td>
</tr>
<tr cond="!$advanced_mailer_log">
<td>{$lang->msg_advanced_mailer_log_is_empty}</td>
</tr>
</tbody>
</table>
<div class="x_clearfix">
<form class="x_pagination x_pull-left" style="margin-top:8px" action="{Context::getUrl('')}" method="post" no-error-return-url="true">
<input loop="$param => $key, $val" cond="!in_array($key, array('mid', 'vid', 'act'))" type="hidden" name="{$key}" value="{$val}" />
<ul>
<li class="x_disabled"|cond="$page == 1"><a href="{getUrl('page', '')}">&laquo; {$lang->first_page}</a></li>
<!--@while($page_no = $page_navigation->getNextPage())-->
<li class="x_active"|cond="$page_no == $page"><a href="{getUrl('page', $page_no)}">{$page_no}</a></li>
<!--@end-->
<li class="x_disabled"|cond="$page == $page_navigation->last_page"><a href="{getUrl('page', $page_navigation->last_page)}">{$lang->last_page} &raquo;</a></li>
</ul>
</form>
<form class="x_pull-right x_input-append" style="margin-top:8px" action="{Context::getUrl('')}" method="post">
<input type="hidden" name="module" value="advanced_mailer" />
<input type="hidden" name="act" value="procAdvanced_mailerAdminClearSentMail" />
<input type="hidden" name="status" value="{$advanced_mailer_status}" />
<select name="clear_before_days" style="width:120px">
<option value="0">{$lang->cmd_advanced_mailer_clear_log_condition_all}</option>
<option value="1">{sprintf($lang->cmd_advanced_mailer_clear_log_condition, 1)}</option>
<option value="3">{sprintf($lang->cmd_advanced_mailer_clear_log_condition, 3)}</option>
<option value="7" selected="selected">{sprintf($lang->cmd_advanced_mailer_clear_log_condition, 7)}</option>
<option value="14">{sprintf($lang->cmd_advanced_mailer_clear_log_condition, 14)}</option>
<option value="30">{sprintf($lang->cmd_advanced_mailer_clear_log_condition, 30)}</option>
<option value="60">{sprintf($lang->cmd_advanced_mailer_clear_log_condition, 60)}</option>
</select>
<button class="x_btn" type="submit" disabled="disabled"|cond="!count($advanced_mailer_log)">{$lang->cmd_advanced_mailer_clear_log_button}</button>
</form>
</div>

View file

@ -0,0 +1,176 @@
<?php
class MailTest extends \Codeception\TestCase\Test
{
public function testGetSetDefaultDriver()
{
$driver = Rhymix\Framework\Mail::getDefaultDriver();
$this->assertInstanceOf('\\Rhymix\\Framework\\Drivers\\MailInterface', $driver);
$driver = Rhymix\Framework\Drivers\Mail\Dummy::getInstance(array());
Rhymix\Framework\Mail::setDefaultDriver($driver);
$this->assertEquals($driver, Rhymix\Framework\Mail::getDefaultDriver());
}
public function testGetSupportedDrivers()
{
$drivers = Rhymix\Framework\Mail::getSupportedDrivers();
$this->assertTrue(isset($drivers['dummy']));
$this->assertTrue(isset($drivers['mailfunction']));
$this->assertTrue(isset($drivers['smtp']));
$this->assertEquals('SMTP', $drivers['smtp']['name']);
$this->assertEquals(array('api_token'), $drivers['sparkpost']['required']);
$this->assertNotEmpty($drivers['woorimail']['spf_hint']);
}
public function testSenderAndRecipients()
{
$mail = new Rhymix\Framework\Mail;
$this->assertNull($mail->getFrom());
$mail->setFrom('devops@rhymix.org', 'Rhymix Developers');
$this->assertEquals('Rhymix Developers <devops@rhymix.org>', $mail->getFrom());
$this->assertEquals(0, count($mail->message->getTo()));
$mail->addTo('whoever@rhymix.org', 'Name');
$this->assertEquals(array('whoever@rhymix.org' => 'Name'), $mail->message->getTo());
$this->assertEquals(0, count($mail->message->getCc()));
$mail->addCc('whatever@rhymix.org', 'Nick');
$this->assertEquals(array('whatever@rhymix.org' => 'Nick'), $mail->message->getCc());
$this->assertEquals(0, count($mail->message->getBcc()));
$mail->addBcc('wherever@rhymix.org', 'User');
$this->assertEquals(array('wherever@rhymix.org' => 'User'), $mail->message->getBcc());
$this->assertEquals(0, count($mail->message->getReplyTo()));
$mail->setReplyTo('replyto@rhymix.org');
$this->assertEquals(array('replyto@rhymix.org' => ''), $mail->message->getReplyTo());
$recipients = $mail->getRecipients();
$this->assertEquals(3, count($recipients));
$this->assertContains('Name <whoever@rhymix.org>', $recipients);
$this->assertContains('Nick <whatever@rhymix.org>', $recipients);
$this->assertContains('User <wherever@rhymix.org>', $recipients);
}
public function testMiscHeaders()
{
$mail = new Rhymix\Framework\Mail;
$mail->setReturnPath('envelope@rhymix.org');
$this->assertEquals('envelope@rhymix.org', $mail->message->getReturnPath());
$mail->setMessageID('some.random.string@rhymix.org');
$this->assertEquals('some.random.string@rhymix.org', $mail->message->getId());
$mail->setInReplyTo('<previous.message@rhymix.org>');
$this->assertEquals('<previous.message@rhymix.org>', $mail->message->getHeaders()->get('In-Reply-To')->getValue());
$mail->setReferences('<thread-1@rhymix.org>, <thread-2@rhymix.org>, <thread-3@rhymix.org>');
$this->assertEquals('<thread-1@rhymix.org>, <thread-2@rhymix.org>, <thread-3@rhymix.org>', $mail->message->getHeaders()->get('References')->getValue());
}
public function testMailSubject()
{
$mail = new Rhymix\Framework\Mail;
$mail->setSubject('Foobar!');
$this->assertEquals('Foobar!', $mail->getSubject());
$mail->setTitle('Foobarbazz?');
$this->assertEquals('Foobarbazz?', $mail->getTitle());
}
public function testMailBody()
{
$mail = new Rhymix\Framework\Mail;
$mail->setBody('<p>Hello world!</p>', 'text/html');
$this->assertEquals('<p>Hello world!</p>', $mail->getBody());
$this->assertEquals('text/html', $mail->getContentType());
$mail->setContent('<p>Hello world! Foobar?</p>', 'text/plain');
$this->assertEquals('<p>Hello world! Foobar?</p>', $mail->getBody());
$this->assertEquals('text/plain', $mail->getContentType());
$mail->setBody('<p>Hello foobar...</p>', 'invalid value');
$this->assertEquals('<p>Hello foobar...</p>', $mail->getContent());
$this->assertEquals('text/plain', $mail->getContentType());
$mail->setContentType('html');
$this->assertEquals('text/html', $mail->getContentType());
$mail->setContentType('invalid');
$this->assertEquals('text/plain', $mail->getContentType());
}
public function testMailAttach()
{
$mail = new Rhymix\Framework\Mail;
$success = $mail->attach(\RX_BASEDIR . 'tests/_data/formatter/minify.source.css');
$this->assertTrue($success);
$success = $mail->attach(\RX_BASEDIR . 'tests/_data/formatter/minify.target.css', 'target.css');
$this->assertTrue($success);
$success = $mail->attach(\RX_BASEDIR . 'tests/_data/nonexistent.file.jpg');
$this->assertFalse($success);
$attachments = $mail->getAttachments();
$this->assertEquals(2, count($attachments));
$this->assertEquals('attach', $attachments[0]->type);
$this->assertEquals(\RX_BASEDIR . 'tests/_data/formatter/minify.source.css', $attachments[0]->local_filename);
$this->assertEquals('minify.source.css', $attachments[0]->display_filename);
$this->assertEquals('target.css', $attachments[1]->display_filename);
}
public function testMailEmbed()
{
$mail = new Rhymix\Framework\Mail;
$cid = $mail->embed(\RX_BASEDIR . 'tests/_data/formatter/minify.source.css', 'thisismyrandomcid@rhymix.org');
$this->assertEquals('cid:thisismyrandomcid@rhymix.org', $cid);
$cid = $mail->embed(\RX_BASEDIR . 'tests/_data/formatter/minify.target.css');
$this->assertRegexp('/^cid:[0-9a-z]+@[^@]+$/i', $cid);
}
public function testMailClassCompatibility()
{
\Mail::useGmailAccount('devops@rhymix.org', 'password');
$this->assertInstanceOf('\\Rhymix\\Framework\\Drivers\\Mail\\SMTP', \Mail::getDefaultDriver());
\Mail::useSMTP(null, 'rhymix.org', 'devops@rhymix.org', 'password', 'tls', 587);
$this->assertInstanceOf('\\Rhymix\\Framework\\Drivers\\Mail\\SMTP', \Mail::getDefaultDriver());
$mail = new \Mail;
$mail->setSender('Rhymix', 'devops@rhymix.org');
$this->assertEquals('Rhymix <devops@rhymix.org>', $mail->getSender());
$mail->setReceiptor('Recipient', 'whoever@rhymix.org');
$this->assertEquals('Recipient <whoever@rhymix.org>', $mail->getReceiptor());
$mail->setReceiptor('Another Recipient', 'whatever@rhymix.org');
$this->assertEquals('Another Recipient <whatever@rhymix.org>', $mail->getReceiptor());
$this->assertEquals(1, count($mail->message->getTo()));
$this->assertEquals(0, count($mail->message->getCc()));
$mail->setBcc('bcc-1@rhymix.org');
$mail->setBcc('bcc-2@rhymix.org');
$this->assertEquals(array('bcc-2@rhymix.org' => ''), $mail->message->getBcc());
$content = '<p>Hello world!</p><p>This is a long message to test chunk splitting.</p><p>This feature is only available using the legacy Mail class.</p>';
$mail->setBody($content);
$this->assertEquals(chunk_split(base64_encode($content)), $mail->getHTMLContent());
$this->assertEquals(chunk_split(base64_encode(htmlspecialchars($content))), $mail->getPlainContent());
$mail->addAttachment(\RX_BASEDIR . 'tests/_data/formatter/minify.target.css', 'target.css');
$cid = $mail->addCidAttachment(\RX_BASEDIR . 'tests/_data/formatter/minify.target.css', 'thisismyrandomcid@rhymix.org');
$this->assertEquals('cid:thisismyrandomcid@rhymix.org', $cid);
$attachments = $mail->getAttachments();
$this->assertEquals(2, count($attachments));
$this->assertEquals('attach', $attachments[0]->type);
$this->assertEquals('target.css', $attachments[0]->display_filename);
$this->assertEquals('embed', $attachments[1]->type);
$this->assertEquals('cid:thisismyrandomcid@rhymix.org', $attachments[1]->cid);
}
}

View file

@ -0,0 +1,22 @@
<?php
use Rhymix\Framework\Helpers\ConfigHelper;
class ConfigHelperTest extends \Codeception\TestCase\Test
{
public function testConsolidate()
{
$member_config = getModel('module')->getModuleConfig('member');
$consolidated = ConfigHelper::consolidate(array(
'dbtype' => array('common:db.type', 'member:nosuchconfig'),
'member' => array('common:no.such.config', 'member:enable_join', 'tobool'),
'nosuch' => array('common:no.such.config', 'member:no.such.config.either', 'intval'),
'single' => 'member:identifier',
));
$this->assertEquals(config('db.type'), $consolidated['dbtype']);
$this->assertEquals(tobool($member_config->enable_join), $consolidated['member']);
$this->assertEquals(0, $consolidated['nosuch']);
$this->assertEquals($member_config->identifier, $consolidated['single']);
}
}

View file

@ -1,4 +1,4 @@
Copyright (c) 2015 Nils Adermann, Jordi Boggiano
Copyright (c) 2016 Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -6,6 +6,10 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'AWSConnectionError' => $vendorDir . '/jmhobbs/swiftmailer-transport-aws-ses/classes/Swift/AWSTransport.php',
'AWSEmptyResponseException' => $vendorDir . '/jmhobbs/swiftmailer-transport-aws-ses/classes/Swift/AWSTransport.php',
'AWSResponse' => $vendorDir . '/jmhobbs/swiftmailer-transport-aws-ses/classes/Swift/AWSTransport.php',
'ChunkedTransferSocket' => $vendorDir . '/jmhobbs/swiftmailer-transport-aws-ses/classes/Swift/AWSTransport.php',
'HTMLPurifier' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.php',
'HTMLPurifier_Arborize' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Arborize.php',
'HTMLPurifier_AttrCollections' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php',
@ -236,6 +240,8 @@ return array(
'HTMLPurifier_VarParser_Native' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php',
'HTMLPurifier_Zipper' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php',
'Hautelook\\Phpass\\PasswordHash' => $vendorDir . '/hautelook/phpass/src/Hautelook/Phpass/PasswordHash.php',
'InvalidHeaderException' => $vendorDir . '/jmhobbs/swiftmailer-transport-aws-ses/classes/Swift/AWSTransport.php',
'InvalidOperationException' => $vendorDir . '/jmhobbs/swiftmailer-transport-aws-ses/classes/Swift/AWSTransport.php',
'JBBCode\\CodeDefinition' => $vendorDir . '/jbbcode/jbbcode/JBBCode/CodeDefinition.php',
'JBBCode\\CodeDefinitionBuilder' => $vendorDir . '/jbbcode/jbbcode/JBBCode/CodeDefinitionBuilder.php',
'JBBCode\\CodeDefinitionSet' => $vendorDir . '/jbbcode/jbbcode/JBBCode/CodeDefinitionSet.php',
@ -365,6 +371,11 @@ return array(
'Requests_Utility_CaseInsensitiveDictionary' => $vendorDir . '/rmccue/requests/library/Requests/Utility/CaseInsensitiveDictionary.php',
'Requests_Utility_FilteredIterator' => $vendorDir . '/rmccue/requests/library/Requests/Utility/FilteredIterator.php',
'Sunra\\PhpSimple\\HtmlDomParser' => $vendorDir . '/sunra/php-simple-html-dom-parser/Src/Sunra/PhpSimple/HtmlDomParser.php',
'Swift_AWSInputByteStream' => $vendorDir . '/jmhobbs/swiftmailer-transport-aws-ses/classes/Swift/AWSInputByteStream.php',
'Swift_AWSTransport' => $vendorDir . '/jmhobbs/swiftmailer-transport-aws-ses/classes/Swift/AWSTransport.php',
'Swift_Events_ResponseReceivedListener' => $vendorDir . '/jmhobbs/swiftmailer-transport-aws-ses/classes/Swift/Events/ResponseReceivedListener.php',
'Swift_Response_AWSResponse' => $vendorDir . '/jmhobbs/swiftmailer-transport-aws-ses/classes/Swift/Response/AWSResponse.php',
'Swift_Transport_AWSTransport' => $vendorDir . '/jmhobbs/swiftmailer-transport-aws-ses/classes/Swift/Transport/AWSTransport.php',
'TrueBV\\Punycode' => $vendorDir . '/true/punycode/src/Punycode.php',
'lessc' => $vendorDir . '/leafo/lessphp/lessc.inc.php',
'lessc_formatter_classic' => $vendorDir . '/leafo/lessphp/lessc.inc.php',

View file

@ -6,7 +6,7 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'2c102faa651ef8ea5874edb585946bce' => $vendorDir . '/swiftmailer/swiftmailer/lib/swift_required.php',
'8170285c807a9f24f165f37b15bc9a36' => $vendorDir . '/defuse/php-encryption/Crypto.php',
'2cffec82183ee1cea088009cef9a6fc3' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
'2c102faa651ef8ea5874edb585946bce' => $vendorDir . '/swiftmailer/swiftmailer/lib/swift_required.php',
);

View file

@ -12,4 +12,5 @@ return array(
'JBBCode' => array($vendorDir . '/jbbcode/jbbcode'),
'Hautelook' => array($vendorDir . '/hautelook/phpass/src'),
'HTMLPurifier' => array($vendorDir . '/ezyang/htmlpurifier/library'),
'' => array($vendorDir . '/jmhobbs/swiftmailer-transport-aws-ses/classes'),
);

View file

@ -188,113 +188,6 @@
"sockets"
]
},
{
"name": "matthiasmullie/path-converter",
"version": "1.0.7",
"version_normalized": "1.0.7.0",
"source": {
"type": "git",
"url": "https://github.com/matthiasmullie/path-converter.git",
"reference": "83609c1bb251b2540eba912615571a501a0a06a6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/matthiasmullie/path-converter/zipball/83609c1bb251b2540eba912615571a501a0a06a6",
"reference": "83609c1bb251b2540eba912615571a501a0a06a6",
"shasum": ""
},
"require": {
"ext-pcre": "*",
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "~4.8",
"satooshi/php-coveralls": "~1.0"
},
"time": "2016-01-07 00:41:13",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"MatthiasMullie\\PathConverter\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Matthias Mullie",
"email": "pathconverter@mullie.eu",
"homepage": "http://www.mullie.eu",
"role": "Developer"
}
],
"description": "Relative path converter",
"homepage": "http://github.com/matthiasmullie/path-converter",
"keywords": [
"converter",
"path",
"paths",
"relative"
]
},
{
"name": "swiftmailer/swiftmailer",
"version": "v5.4.1",
"version_normalized": "5.4.1.0",
"source": {
"type": "git",
"url": "https://github.com/swiftmailer/swiftmailer.git",
"reference": "0697e6aa65c83edf97bb0f23d8763f94e3f11421"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/0697e6aa65c83edf97bb0f23d8763f94e3f11421",
"reference": "0697e6aa65c83edf97bb0f23d8763f94e3f11421",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"mockery/mockery": "~0.9.1,<0.9.4"
},
"time": "2015-06-06 14:19:39",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.4-dev"
}
},
"installation-source": "dist",
"autoload": {
"files": [
"lib/swift_required.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Chris Corbyn"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Swiftmailer, free feature-rich PHP mailer",
"homepage": "http://swiftmailer.org",
"keywords": [
"email",
"mail",
"mailer"
]
},
{
"name": "true/punycode",
"version": "v2.0.2",
@ -768,5 +661,156 @@
"scss",
"stylesheet"
]
},
{
"name": "matthiasmullie/path-converter",
"version": "1.0.8",
"version_normalized": "1.0.8.0",
"source": {
"type": "git",
"url": "https://github.com/matthiasmullie/path-converter.git",
"reference": "7c36e5cafa95dd20008d19b153b506cffa8c2848"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/matthiasmullie/path-converter/zipball/7c36e5cafa95dd20008d19b153b506cffa8c2848",
"reference": "7c36e5cafa95dd20008d19b153b506cffa8c2848",
"shasum": ""
},
"require": {
"ext-pcre": "*",
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "~4.8"
},
"time": "2016-04-27 10:38:05",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"MatthiasMullie\\PathConverter\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Matthias Mullie",
"email": "pathconverter@mullie.eu",
"homepage": "http://www.mullie.eu",
"role": "Developer"
}
],
"description": "Relative path converter",
"homepage": "http://github.com/matthiasmullie/path-converter",
"keywords": [
"converter",
"path",
"paths",
"relative"
]
},
{
"name": "swiftmailer/swiftmailer",
"version": "v5.4.2",
"version_normalized": "5.4.2.0",
"source": {
"type": "git",
"url": "https://github.com/swiftmailer/swiftmailer.git",
"reference": "d8db871a54619458a805229a057ea2af33c753e8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/d8db871a54619458a805229a057ea2af33c753e8",
"reference": "d8db871a54619458a805229a057ea2af33c753e8",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"mockery/mockery": "~0.9.1,<0.9.4"
},
"time": "2016-05-01 08:45:47",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.4-dev"
}
},
"installation-source": "dist",
"autoload": {
"files": [
"lib/swift_required.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Chris Corbyn"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Swiftmailer, free feature-rich PHP mailer",
"homepage": "http://swiftmailer.org",
"keywords": [
"email",
"mail",
"mailer"
]
},
{
"name": "jmhobbs/swiftmailer-transport-aws-ses",
"version": "0.9.2",
"version_normalized": "0.9.2.0",
"source": {
"type": "git",
"url": "https://github.com/jmhobbs/Swiftmailer-Transport--AWS-SES.git",
"reference": "10110a450225a19b5095e7313a5c7c4b43bba3b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jmhobbs/Swiftmailer-Transport--AWS-SES/zipball/10110a450225a19b5095e7313a5c7c4b43bba3b6",
"reference": "10110a450225a19b5095e7313a5c7c4b43bba3b6",
"shasum": ""
},
"require": {
"php": ">=5.2.0",
"swiftmailer/swiftmailer": ">=4.0.0"
},
"time": "2014-11-12 23:51:28",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"": "classes/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "John Hobbs",
"email": "john@velvetcache.org"
}
],
"description": "Add AWS SES support to Swiftmailer",
"keywords": [
"aws",
"email",
"ses",
"swiftmailer"
]
}
]

View file

@ -0,0 +1,3 @@
composer.lock
vendor/*
example/config.php

View file

@ -0,0 +1,19 @@
Copyright (c) 2011 John Hobbs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE

View file

@ -0,0 +1,67 @@
# What is it?
It's a simple transport for use with Swiftmailer to send mail over AWS SES.
As on December 2011, Amazon [provides an SMTP interface to SES](http://aws.amazon.com/ses/faqs/#21), so you may prefer to use Swiftmailer's built in SMTP transport.
# Where do I put it?
Whereever you want, so long as you include it in your code.
Otherwise Swift can autoload it if you put the files in this directory:
[swift library root]/classes/Swift/AWSTransport.php
# How do I use it?
Like any other Swiftmailer transport:
//Create the Transport
$transport = Swift_AWSTransport::newInstance( 'AWS_ACCESS_KEY', 'AWS_SECRET_KEY' );
//Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
$mailer->send($message);
# Symfony1.X configuration
```yaml
# app/frontend/config/factories.yml
all:
mailer:
class: sfMailer
param:
transport:
class: Swift_AWSTransport
accessKeyId: your-access-key
secretKey: Y0uR-$3cr3t5-k3y
debug: false
endpoint: 'https://email.us-east-1.amazonaws.com/' # make sure to use trailing slash !
```
# How do I get the message ID on send?
You need to register the Swift_Events_ResponseReceivedListener plugin with a callback. See example/responseListener.php for details.
$transport->registerPlugin(
new Swift_Events_ResponseReceivedListener( function ( $message, $body ) {
echo sprintf( "Message-ID %s.\n", $body->SendRawEmailResult->MessageId );
})
);
# Swiftmailer Version
Please note that some users [have had issues with older versions of Swiftmailer](https://github.com/jmhobbs/Swiftmailer-Transport--AWS-SES/issues/13).
Versions 4.1.3 and up should work fine.
# Credits
* @jmhobbs - Original development
* @bertrandom - Bug fix
* @themouette - Plugins & Symfony compatible
* @jonatrey & @faz - Debugging and Testing issue #13
* @casconed - Made debug function more robust, issue #21
* @martijngastkemper - Added responseReceived event to get message id from AWS

View file

@ -0,0 +1,90 @@
<?php
class Swift_AWSInputByteStream implements Swift_InputByteStream {
public function __construct( $socket ) {
$this->socket = $socket;
$this->buffer = '';
$this->counter = 0;
}
/**
* Writes $bytes to the end of the stream.
*
* Writing may not happen immediately if the stream chooses to buffer. If
* you want to write these bytes with immediate effect, call {@link commit()}
* after calling write().
*
* This method returns the sequence ID of the write (i.e. 1 for first, 2 for
* second, etc etc).
*
* @param string $bytes
* @return int
*/
public function write($bytes) {
$block = $this->buffer . $bytes;
$block_size = strlen( $block );
$encoded = base64_encode( $block );
$setback = 0;
while( substr( $encoded, -1 ) === '=' ) {
++$setback;
if( $setback >= $block_size ) {
$this->buffer = $block;
return ++$this->counter;
}
$encoded = base64_encode( substr( $block, 0, $setback * -1 ) );
}
if( $setback > 0 ) {
$this->buffer = substr( $block, $setback * -1 );
}
else {
$this->buffer = '';
}
unset( $block );
$this->socket->write( urlencode( $encoded ) );
unset( $encoded );
return ++$this->counter;
}
/**
* For any bytes that are currently buffered inside the stream, force them
* off the buffer.
*/
public function commit() {
// NOP - Since we have a required packet offset (3-bytes), we can't commit arbitrarily.
}
public function flushBuffers() {
if( strlen( $this->buffer ) > 0 ) {
$this->socket->write( urlencode( base64_encode( $this->buffer ) ) );
}
$this->socket->finishWrite();
}
/**
* Attach $is to this stream.
* The stream acts as an observer, receiving all data that is written.
* All {@link write()} and {@link flushBuffers()} operations will be mirrored.
*
* @param Swift_InputByteStream $is
*/
public function bind(Swift_InputByteStream $is){}
/**
* Remove an already bound stream.
* If $is is not bound, no errors will be raised.
* If the stream currently has any buffered data it will be written to $is
* before unbinding occurs.
*
* @param Swift_InputByteStream $is
*/
public function unbind(Swift_InputByteStream $is){}
}

View file

@ -0,0 +1,356 @@
<?php
/*
* This file requires SwiftMailer.
* (c) 2011 John Hobbs
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Sends Messages over AWS.
* @package Swift
* @subpackage Transport
* @author John Hobbs
*/
class Swift_AWSTransport extends Swift_Transport_AWSTransport {
/** the service access key */
private $AWSAccessKeyId;
/** the service secret key */
private $AWSSecretKey;
/** the service endpoint */
private $endpoint;
/**
* Debugging helper.
*
* If false, no debugging will be done.
* If true, debugging will be done with error_log.
* Otherwise, this should be a callable, and will recieve the debug message as the first argument.
*
* @seealso Swift_AWSTransport::setDebug()
*/
private $debug;
/** the response */
private $response;
/**
* Create a new AWSTransport.
* @param string $AWSAccessKeyId Your access key.
* @param string $AWSSecretKey Your secret key.
* @param boolean $debug Set to true to enable debug messages in error log.
* @param string $endpoint The AWS endpoint to use.
*/
public function __construct($AWSAccessKeyId = null , $AWSSecretKey = null, $debug = false, $endpoint = 'https://email.us-east-1.amazonaws.com/') {
call_user_func_array(
array($this, 'Swift_Transport_AWSTransport::__construct'),
Swift_DependencyContainer::getInstance()
->createDependenciesFor('transport.aws')
);
$this->AWSAccessKeyId = $AWSAccessKeyId;
$this->AWSSecretKey = $AWSSecretKey;
$this->endpoint = $endpoint;
$this->debug = $debug;
}
/**
* Create a new AWSTransport.
* @param string $AWSAccessKeyId Your access key.
* @param string $AWSSecretKey Your secret key.
*/
public static function newInstance( $AWSAccessKeyId , $AWSSecretKey ) {
return new Swift_AWSTransport( $AWSAccessKeyId , $AWSSecretKey );
}
public function setAccessKeyId($val) {
$this->AWSAccessKeyId = $val;
}
public function setSecretKey($val) {
$this->AWSSecretKey = $val;
}
public function setDebug($val) {
$this->debug = $val;
}
public function setEndpoint($val) {
$this->endpoint = $val;
}
public function getResponse() {
return $this->response;
}
protected function _debug ( $message ) {
if ( true === $this->debug ) {
error_log( $message );
} elseif ( is_callable($this->debug) ) {
call_user_func( $this->debug, $message );
}
}
/**
* Send the given Message.
*
* Recipient/sender data will be retreived from the Message API.
* The return value is the number of recipients who were accepted for delivery.
*
* @param Swift_Mime_Message $message
* @param string[] &$failedRecipients to collect failures by-reference
* @return int
* @throws AWSConnectionError
*/
public function send( Swift_Mime_Message $message, &$failedRecipients = null ) {
if ($evt = $this->_eventDispatcher->createSendEvent($this, $message))
{
$this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed');
if ($evt->bubbleCancelled())
{
return 0;
}
}
$this->response = $this->_doSend($message, $failedRecipients);
$this->_debug("=== Start AWS Response ===");
$this->_debug($this->response->body);
$this->_debug("=== End AWS Response ===");
$success = (200 == $this->response->code);
if ($respEvent = $this->_eventDispatcher->createResponseEvent($this, new Swift_Response_AWSResponse( $message, $this->response->xml ), $success))
$this->_eventDispatcher->dispatchEvent($respEvent, 'responseReceived');
if ($evt)
{
$evt->setResult($success ? Swift_Events_SendEvent::RESULT_SUCCESS : Swift_Events_SendEvent::RESULT_FAILED);
$this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed');
}
if( $success ) {
return count((array) $message->getTo());
}
else {
return 0;
}
}
/**
* do send through the API
*
* @param Swift_Mime_Message $message
* @param string[] &$failedRecipients to collect failures by-reference
* @return AWSResponse
*/
protected function _doSend( Swift_Mime_Message $message, &$failedRecipients = null )
{
$date = date( 'D, j F Y H:i:s O' );
if( function_exists( 'hash_hmac' ) and in_array( 'sha1', hash_algos() ) ) {
$hmac = base64_encode( hash_hmac( 'sha1', $date, $this->AWSSecretKey, true ) );
}
else {
$hmac = $this->calculate_RFC2104HMAC( $date, $this->AWSSecretKey );
}
$auth = "AWS3-HTTPS AWSAccessKeyId=" . $this->AWSAccessKeyId . ", Algorithm=HmacSHA1, Signature=" . $hmac;
$host = parse_url( $this->endpoint, PHP_URL_HOST );
$path = parse_url( $this->endpoint, PHP_URL_PATH );
$fp = fsockopen( 'ssl://' . $host , 443, $errno, $errstr, 30 );
if( ! $fp ) {
throw new AWSConnectionError( "$errstr ($errno)" );
}
$socket = new ChunkedTransferSocket( $fp, $host, $path );
$socket->header("Date", $date);
$socket->header("X-Amzn-Authorization", $auth);
$socket->write("Action=SendRawEmail&RawMessage.Data=");
$ais = new Swift_AWSInputByteStream($socket);
$message->toByteStream($ais);
$ais->flushBuffers();
$result = $socket->read();
return $result;
}
/**
* Cribbed from php-aws - Thanks!
* https://github.com/tylerhall/php-aws/blob/master/class.awis.php
* (c) Tyler Hall
* MIT License
*/
protected function calculate_RFC2104HMAC($data, $key) {
return base64_encode (
pack("H*", sha1((str_pad($key, 64, chr(0x00))
^(str_repeat(chr(0x5c), 64))) .
pack("H*", sha1((str_pad($key, 64, chr(0x00))
^(str_repeat(chr(0x36), 64))) . $data))))
);
}
public function isStarted() {}
public function start() {}
public function stop() {}
/**
* Register a plugin.
*
* @param Swift_Events_EventListener $plugin
*/
public function registerPlugin(Swift_Events_EventListener $plugin)
{
$this->_eventDispatcher->bindEventListener($plugin);
}
} // AWSTransport
/**
* Convenience methods to use a socket for chunked transfer in HTTP
*/
class ChunkedTransferSocket {
/**
* @param $socket
* @param $host
* @param $path
* @param $method
*/
public function __construct( $socket, $host, $path, $method="POST" ) {
$this->socket = $socket;
$this->write_started = false;
$this->write_finished = false;
$this->read_started = false;
fwrite( $this->socket, "$method $path HTTP/1.1\r\n" );
$this->header( "Host", $host );
if( "POST" == $method ) {
$this->header( "Content-Type", "application/x-www-form-urlencoded" );
}
$this->header( "Connection", "close" );
$this->header( "Transfer-Encoding", "chunked" );
}
/**
* Add an HTTP header
*
* @param $header
* @param $value
*/
public function header ( $header, $value ) {
if( $this->write_started ) { throw new InvalidOperationException( "Can not write header, body writing has started." ); }
fwrite( $this->socket, "$header: $value\r\n" );
fflush( $this->socket );
}
/**
* Write a chunk of data
* @param $chunk
*/
public function write ( $chunk ) {
if( $this->write_finished ) { throw new InvalidOperationException( "Can not write, reading has started." ); }
if( ! $this->write_started ) {
fwrite( $this->socket, "\r\n" ); // Start message body
$this->write_started = true;
}
fwrite( $this->socket, sprintf( "%x\r\n", strlen( $chunk ) ) );
fwrite( $this->socket, $chunk . "\r\n" );
fflush( $this->socket );
}
/**
* Finish writing chunks and get ready to read.
*/
public function finishWrite () {
$this->write("");
$this->write_finished = true;
}
/**
* Read the socket for a response
*/
public function read () {
if( ! $this->write_finished ) { $this->finishWrite(); }
$this->read_started = true;
$response = new AWSResponse();
while( ! feof( $this->socket ) ) {
$response->line( fgets( $this->socket ) );
}
$response->complete();
fclose( $this->socket );
return $response;
}
}
/**
* A wrapper to parse an AWS HTTP response
*/
class AWSResponse {
public $headers = array();
public $code = 0;
public $message = '';
public $body = '';
public $xml = null;
const STATE_EMPTY = 0;
const STATE_HEADERS = 1;
const STATE_BODY = 2;
protected $state = self::STATE_EMPTY;
public function line ( $line ) {
switch( $this->state ) {
case self::STATE_EMPTY:
if( ! $line ) {
throw new AWSEmptyResponseException();
}
$split = explode( ' ', $line );
$this->code = $split[1];
$this->message = implode( array_slice( $split, 2 ), ' ' );
$this->state = self::STATE_HEADERS;
break;
case self::STATE_HEADERS:
if( "\r\n" == $line ) {
$this->state = self::STATE_BODY;
break;
}
$pos = strpos( $line, ':' );
if( false === $pos ) { throw new InvalidHeaderException( $line ); }
$key = substr( $line, 0, $pos );
$this->headers[$key] = substr( $line, $pos );
break;
case self::STATE_BODY:
$this->body .= $line;
break;
}
}
public function complete () {
$this->xml = simplexml_load_string( $this->body );
}
}
class AWSConnectionError extends Exception {}
class InvalidOperationException extends Exception {}
class InvalidHeaderException extends Exception {}
class AWSEmptyResponseException extends Exception {}

View file

@ -0,0 +1,19 @@
<?php
class Swift_Events_ResponseReceivedListener
implements Swift_Events_ResponseListener
{
private $callback;
public function __construct( callable $callback )
{
$this->callback = $callback;
}
public function responseReceived( \Swift_Events_ResponseEvent $event )
{
$callback = $this->callback;
$callback( $event->getResponse()->getMessage(), $event->getResponse()->getBody() );
}
}

View file

@ -0,0 +1,36 @@
<?php
class Swift_Response_AWSResponse {
protected $message;
protected $body;
public function __construct( Swift_Mime_Message $message, $body = null )
{
$this->message = $message;
$this->body = $body;
}
function getMessage()
{
return $this->message;
}
function getBody()
{
return $this->body;
}
function setMessage( $message )
{
$this->message = $message;
return $this;
}
function setBody( $body )
{
$this->body = $body;
return $this;
}
}

View file

@ -0,0 +1,35 @@
<?php
/**
* This file declare the Swist_Transport_AWSTransport class.
*
* @package Swift
* @subpackage Transport
* @author Julien Muetton <julien_muetton@carpe-hora.com>
* @copyright (c) Carpe Hora SARL 2011
* @since 2011-10-07
*/
/**
* the base class for aws transport
*/
abstract class Swift_Transport_AWSTransport implements Swift_Transport
{
/** The event dispatcher from the plugin API */
protected $_eventDispatcher;
/**
* Constructor.
*/
public function __construct(Swift_Events_EventDispatcher $eventDispatcher)
{
$this->_eventDispatcher = $eventDispatcher;
}
} // END OF Swist_Transport_AWSTransport
// now register dependancies
Swift_DependencyContainer::getInstance()
-> register('transport.aws')
-> withDependencies(array('transport.eventdispatcher'))
;

View file

@ -0,0 +1,20 @@
{
"name": "jmhobbs/swiftmailer-transport-aws-ses",
"type": "library",
"description": "Add AWS SES support to Swiftmailer",
"keywords": [ "email", "swiftmailer", "SES", "AWS" ],
"license": "MIT",
"authors": [
{
"name": "John Hobbs",
"email": "john@velvetcache.org"
}
],
"require": {
"php": ">=5.2.0",
"swiftmailer/swiftmailer": ">=4.0.0"
},
"autoload": {
"psr-0": { "": "classes/" }
}
}

View file

@ -0,0 +1,13 @@
<?php
// AWS Credentials
define( 'AWSAccessKeyId', 'your-access-key' );
define( 'AWSSecretKey', 'your-secret-key' );
// Email address to send test email from
define( 'FROM_ADDRESS', 'change-this@to-your-email.com' );
// Email address to send test email to
define( 'TO_ADDRESS', 'change-this@as-well-please.com' );
// Set the correct endpoint. http://docs.aws.amazon.com/general/latest/gr/rande.html#ses_region
define( 'AWSSESEndpoint', 'https://email.us-east-1.amazonaws.com/' );

View file

@ -0,0 +1,38 @@
<?php
/*
* Example sending email with AWS.
*
* 1. Run composer.phar install in the root (next to compser.json)
* 2. Copy config.php.example to config.php and add your AWS credentials
* 3. Run this script!
*/
require_once(__DIR__ . '/../vendor/autoload.php');
require_once('./config.php');
$transport = Swift_AWSTransport::newInstance( AWSAccessKeyId, AWSSecretKey );
$transport->setEndpoint( AWSSESEndpoint );
$transport->setDebug( true ); // Print the response from AWS to the error log for debugging.
$transport->registerPlugin(
new Swift_Events_ResponseReceivedListener( function ( $message, $body ) {
echo sprintf( "Message \"%s\" sent by SES with Message-ID %s. Now you can store it in your database to handle bounces, complaints and deliveries.\n", $message->getSubject(), $body->SendRawEmailResult->MessageId );
})
);
//Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance( $transport );
//Create the message
$message = Swift_Message::newInstance()
->setSubject( 'Testing Swiftmailer SES' )
->setFrom( array( FROM_ADDRESS ) )
->setTo( array( TO_ADDRESS ) )
->setBody( "<p>Dude, I'm <b>totally</b> sending you email via AWS.</p>", 'text/html' )
->addPart( "Dude, I'm _totally_ sending you email via AWS.", 'text/plain' );
echo "Sending\n";
try {
echo "Sent: " . $mailer->send( $message ) . "\n";
}
catch( AWSEmptyResponseException $e ) {
echo $e . "\n";
}

View file

@ -0,0 +1,32 @@
<?php
/*
* Example sending email with AWS.
*
* 1. Run composer.phar install in the root (next to compser.json)
* 2. Copy config.php.example to config.php and add your AWS credentials
* 3. Run this script!
*/
require_once(__DIR__ . '/../vendor/autoload.php');
require_once('./config.php');
$transport = Swift_AWSTransport::newInstance( AWSAccessKeyId, AWSSecretKey );
$transport->setDebug( true ); // Print the response from AWS to the error log for debugging.
//Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance( $transport );
//Create the message
$message = Swift_Message::newInstance()
->setSubject( 'Testing Swiftmailer SES' )
->setFrom( array( FROM_ADDRESS ) )
->setTo( array( TO_ADDRESS ) )
->setBody( "<p>Dude, I'm <b>totally</b> sending you email via AWS.</p>", 'text/html' )
->addPart( "Dude, I'm _totally_ sending you email via AWS.", 'text/plain' );
echo "Sending\n";
try {
echo "Sent: " . $mailer->send( $message ) . "\n";
}
catch( AWSEmptyResponseException $e ) {
echo $e . "\n";
}

View file

@ -1,3 +0,0 @@
src_dir: src
coverage_clover: build/logs/clover.xml
json_path: build/logs/coveralls-upload.json

View file

@ -18,8 +18,7 @@
"ext-pcre": "*"
},
"require-dev": {
"phpunit/phpunit": "~4.8",
"satooshi/php-coveralls": "~1.0"
"phpunit/phpunit": "~4.8"
},
"autoload": {
"psr-4": {

View file

@ -48,12 +48,12 @@ class Converter
$to = realpath($to) ?: $to;
}
$from = $this->normalize($from);
$to = $this->normalize($to);
$from = $this->dirname($from);
$to = $this->dirname($to);
$from = $this->normalize($from);
$to = $this->normalize($to);
$this->from = $from;
$this->to = $to;
}

View file

@ -1,17 +1,13 @@
language: php
php:
- 5.3
- 5.4
- 5.5
- 5.6
- hhvm-nightly
sudo: false
before_script:
- cp tests/acceptance.conf.php.default tests/acceptance.conf.php
- cp tests/smoke.conf.php.default tests/smoke.conf.php
- composer self-update
- composer update --no-interaction --prefer-source
- gem install mime-types -v 2.99.1
- gem install mailcatcher
- mailcatcher --smtp-port 4456
@ -19,7 +15,14 @@ script:
- phpunit --verbose
matrix:
allow_failures:
- php: 5.6
- php: hhvm-nightly
fast_finish: true
include:
- php: 5.3
- php: 5.4
- php: 5.5
- php: 5.6
- php: 7.0
- php: hhvm
allow_failures:
- php: 7.0
- php: hhvm
fast_finish: true

View file

@ -1,6 +1,21 @@
Changelog
=========
5.4.2 (2016-05-01)
------------------
* fixed support for IPv6 sockets
* added auto-retry when sending messages from the memory spool
* fixed consecutive read calls in Swift_ByteStream_FileByteStream
* added support for iso-8859-15 encoding
* fixed PHP mail extra params on missing reversePath
* added methods to set custom stream context options
* fixed charset changes in QpContentEncoderProxy
* added return-path header to the ignoredHeaders list of DKIMSigner
* fixed crlf for subject using mail
* fixed add soft line break only when necessary
* fixed escaping command-line args to Sendmail
5.4.1 (2015-06-06)
------------------

View file

@ -1,4 +1,4 @@
Copyright (c) 2013 Fabien Potencier
Copyright (c) 2013-2016 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -6,7 +6,6 @@ It is released under the MIT license.
Homepage: http://swiftmailer.org
Documentation: http://swiftmailer.org/docs
Mailing List: http://groups.google.com/group/swiftmailer
Bugs: https://github.com/swiftmailer/swiftmailer/issues
Repository: https://github.com/swiftmailer/swiftmailer

View file

@ -1 +1 @@
Swift-5.4.1
Swift-5.4.2

View file

@ -23,6 +23,11 @@
"autoload": {
"files": ["lib/swift_required.php"]
},
"autoload-dev": {
"psr-0": {
"Swift_": "tests/unit"
}
},
"extra": {
"branch-alias": {
"dev-master": "5.4-dev"

View file

@ -21,11 +21,11 @@ System Requirements
The basic requirements to operate Swift Mailer are extremely minimal and
easily achieved. Historically, Swift Mailer has supported both PHP 4 and PHP 5
by following a parallel development workflow. Now in it's fourth major
version, and Swift Mailer operates on servers running PHP 5.2 or higher.
version, and Swift Mailer operates on servers running PHP 5.3.3 or higher.
The library aims to work with as many PHP 5 projects as possible:
* PHP 5.2 or higher, with the SPL extension (standard)
* PHP 5.3.3 or higher, with the SPL extension (standard)
* Limited network access to connect to remote SMTP servers

View file

@ -22,6 +22,8 @@ abstract class Swift_ByteStream_AbstractFilterableInputStream implements Swift_I
/**
* StreamFilters.
*
* @var Swift_StreamFilter[]
*/
private $_filters = array();

View file

@ -82,9 +82,7 @@ class Swift_ByteStream_ArrayByteStream implements Swift_InputByteStream, Swift_O
// Don't use array slice
$end = $length + $this->_offset;
$end = $this->_arraySize < $end
? $this->_arraySize
: $end;
$end = $this->_arraySize < $end ? $this->_arraySize : $end;
$ret = '';
for (; $this->_offset < $end; ++$this->_offset) {
$ret .= $this->_array[$this->_offset];

View file

@ -139,11 +139,13 @@ class Swift_ByteStream_FileByteStream extends Swift_ByteStream_AbstractFilterabl
private function _getReadHandle()
{
if (!isset($this->_reader)) {
if (!$this->_reader = fopen($this->_path, 'rb')) {
$pointer = @fopen($this->_path, 'rb');
if (!$pointer) {
throw new Swift_IoException(
'Unable to open file for reading ['.$this->_path.']'
);
}
$this->_reader = $pointer;
if ($this->_offset != 0) {
$this->_getReadStreamSeekableStatus();
$this->_seekReadStreamToPosition($this->_offset);

View file

@ -82,7 +82,7 @@ class Swift_CharacterReader_GenericFixedWidthReader implements Swift_CharacterRe
{
$needed = $this->_width - $size;
return ($needed > -1) ? $needed : -1;
return $needed > -1 ? $needed : -1;
}
/**

View file

@ -67,9 +67,9 @@ class Swift_CharacterReader_UsAsciiReader implements Swift_CharacterReader
$byte = reset($bytes);
if (1 == count($bytes) && $byte >= 0x00 && $byte <= 0x7F) {
return 0;
} else {
return -1;
}
return -1;
}
/**

View file

@ -161,10 +161,7 @@ class Swift_CharacterReader_Utf8Reader implements Swift_CharacterReader
}
$needed = self::$length_map[$bytes[0]] - $size;
return ($needed > -1)
? $needed
: -1
;
return $needed > -1 ? $needed : -1;
}
/**

View file

@ -165,9 +165,7 @@ class Swift_CharacterStream_NgCharacterStream implements Swift_CharacterStream
return false;
}
$ret = false;
$length = ($this->_currentPos + $length > $this->_charCount)
? $this->_charCount - $this->_currentPos
: $length;
$length = $this->_currentPos + $length > $this->_charCount ? $this->_charCount - $this->_currentPos : $length;
switch ($this->_mapType) {
case Swift_CharacterReader::MAP_TYPE_FIXED_LEN:
$len = $length * $this->_map;
@ -178,10 +176,6 @@ class Swift_CharacterStream_NgCharacterStream implements Swift_CharacterStream
break;
case Swift_CharacterReader::MAP_TYPE_INVALID:
$end = $this->_currentPos + $length;
$end = $end > $this->_charCount
? $this->_charCount
: $end;
$ret = '';
for (; $this->_currentPos < $length; ++$this->_currentPos) {
if (isset($this->_map[$this->_currentPos])) {
@ -194,9 +188,7 @@ class Swift_CharacterStream_NgCharacterStream implements Swift_CharacterStream
case Swift_CharacterReader::MAP_TYPE_POSITIONS:
$end = $this->_currentPos + $length;
$end = $end > $this->_charCount
? $this->_charCount
: $end;
$end = $end > $this->_charCount ? $this->_charCount : $end;
$ret = '';
$start = 0;
if ($this->_currentPos > 0) {

View file

@ -311,9 +311,9 @@ class Swift_DependencyContainer
return $reflector->newInstanceArgs(
$this->createDependenciesFor($itemName)
);
} else {
return $reflector->newInstance();
}
return $reflector->newInstance();
}
/** Create and register a shared instance of $itemName */
@ -366,8 +366,8 @@ class Swift_DependencyContainer
}
return $collection;
} else {
return $this->lookup($item);
}
return $this->lookup($item);
}
}

View file

@ -198,14 +198,25 @@ class Swift_Encoder_QpEncoder implements Swift_Encoder
}
$enc = $this->_encodeByteSequence($bytes, $size);
if ($currentLine && $lineLen + $size >= $thisLineLength) {
$i = strpos($enc, '=0D=0A');
$newLineLength = $lineLen + ($i === false ? $size : $i);
if ($currentLine && $newLineLength >= $thisLineLength) {
$lines[$lNo] = '';
$currentLine = &$lines[$lNo++];
$thisLineLength = $maxLineLength;
$lineLen = 0;
}
$lineLen += $size;
$currentLine .= $enc;
if ($i === false) {
$lineLen += $size;
} else {
// 6 is the length of '=0D=0A'.
$lineLen = $size - strrpos($enc, '=0D=0A') - 6;
}
}
return $this->_standardize(implode("=\r\n", $lines));

View file

@ -39,7 +39,7 @@ class Swift_FileSpool extends Swift_ConfigurableSpool
if (!file_exists($this->_path)) {
if (!mkdir($this->_path, 0777, true)) {
throw new Swift_IoException('Unable to create Path ['.$this->_path.']');
throw new Swift_IoException(sprintf('Unable to create path "%s".', $this->_path));
}
}
}
@ -108,7 +108,7 @@ class Swift_FileSpool extends Swift_ConfigurableSpool
}
}
throw new Swift_IoException('Unable to create a file for enqueuing Message');
throw new Swift_IoException(sprintf('Unable to create a file for enqueuing Message in "%s".', $this->_path));
}
/**

View file

@ -289,10 +289,7 @@ class Swift_KeyCache_DiskKeyCache implements Swift_KeyCache
private function _getHandle($nsKey, $itemKey, $position)
{
if (!isset($this->_keys[$nsKey][$itemKey])) {
$openMode = $this->hasKey($nsKey, $itemKey)
? 'r+b'
: 'w+b'
;
$openMode = $this->hasKey($nsKey, $itemKey) ? 'r+b' : 'w+b';
$fp = fopen($this->_path.'/'.$nsKey.'/'.$itemKey, $openMode);
$this->_keys[$nsKey][$itemKey] = $fp;
}

View file

@ -69,7 +69,7 @@ class Swift_Mailer
* @param Swift_Mime_Message $message
* @param array $failedRecipients An array of failures by-reference
*
* @return int
* @return int The number of successful recipients. Can be 0 which indicates failure
*/
public function send(Swift_Mime_Message $message, &$failedRecipients = null)
{

View file

@ -16,6 +16,7 @@
class Swift_MemorySpool implements Swift_Spool
{
protected $messages = array();
private $flushRetries = 3;
/**
* Tests if this Transport mechanism has started.
@ -41,6 +42,14 @@ class Swift_MemorySpool implements Swift_Spool
{
}
/**
* @param int $retries
*/
public function setFlushRetries($retries)
{
$this->flushRetries = $retries;
}
/**
* Stores a message in the queue.
*
@ -75,8 +84,25 @@ class Swift_MemorySpool implements Swift_Spool
}
$count = 0;
while ($message = array_pop($this->messages)) {
$count += $transport->send($message, $failedRecipients);
$retries = $this->flushRetries;
while ($retries--) {
try {
while ($message = array_pop($this->messages)) {
$count += $transport->send($message, $failedRecipients);
}
} catch (Swift_TransportException $exception) {
if ($retries) {
// re-queue the message at the end of the queue to give a chance
// to the other messages to be sent, in case the failure was due to
// this message and not just the transport failing
array_unshift($this->messages, $message);
// wait half a second before we try again
usleep(500000);
} else {
throw $exception;
}
}
}
return $count;

View file

@ -69,9 +69,7 @@ class Swift_Mime_Attachment extends Swift_Mime_SimpleMimeEntity
public function setDisposition($disposition)
{
if (!$this->_setHeaderFieldModel('Content-Disposition', $disposition)) {
$this->getHeaders()->addParameterizedHeader(
'Content-Disposition', $disposition
);
$this->getHeaders()->addParameterizedHeader('Content-Disposition', $disposition);
}
return $this;
@ -139,9 +137,7 @@ class Swift_Mime_Attachment extends Swift_Mime_SimpleMimeEntity
$this->setFilename(basename($file->getPath()));
$this->setBody($file, $contentType);
if (!isset($contentType)) {
$extension = strtolower(substr(
$file->getPath(), strrpos($file->getPath(), '.') + 1
));
$extension = strtolower(substr($file->getPath(), strrpos($file->getPath(), '.') + 1));
if (array_key_exists($extension, $this->_mimeTypes)) {
$this->setContentType($this->_mimeTypes[$extension]);

View file

@ -95,15 +95,26 @@ class Swift_Mime_ContentEncoder_QpContentEncoder extends Swift_Encoder_QpEncoder
}
$enc = $this->_encodeByteSequence($bytes, $size);
if ($currentLine && $lineLen + $size >= $thisLineLength) {
$i = strpos($enc, '=0D=0A');
$newLineLength = $lineLen + ($i === false ? $size : $i);
if ($currentLine && $newLineLength >= $thisLineLength) {
$is->write($prepend.$this->_standardize($currentLine));
$currentLine = '';
$prepend = "=\r\n";
$thisLineLength = $maxLineLength;
$lineLen = 0;
}
$lineLen += $size;
$currentLine .= $enc;
if ($i === false) {
$lineLen += $size;
} else {
// 6 is the length of '=0D=0A'.
$lineLen = $size - strrpos($enc, '=0D=0A') - 6;
}
}
if (strlen($currentLine)) {
$is->write($prepend.$this->_standardize($currentLine));

View file

@ -61,6 +61,7 @@ class Swift_Mime_ContentEncoder_QpContentEncoderProxy implements Swift_Mime_Cont
public function charsetChanged($charset)
{
$this->charset = $charset;
$this->safeEncoder->charsetChanged($charset);
}
/**

View file

@ -129,11 +129,11 @@ class Swift_Mime_Grammar
{
if (array_key_exists($name, self::$_grammar)) {
return self::$_grammar[$name];
} else {
throw new Swift_RfcComplianceException(
"No such grammar '".$name."' defined."
);
}
throw new Swift_RfcComplianceException(
"No such grammar '".$name."' defined."
);
}
/**

View file

@ -98,9 +98,7 @@ class Swift_Mime_Headers_ParameterizedHeader extends Swift_Mime_Headers_Unstruct
{
$params = $this->getParameters();
return array_key_exists($parameter, $params)
? $params[$parameter]
: null;
return array_key_exists($parameter, $params) ? $params[$parameter] : null;
}
/**

View file

@ -128,9 +128,7 @@ class Swift_Mime_MimePart extends Swift_Mime_SimpleMimeEntity
*/
public function getDelSp()
{
return ($this->_getHeaderParameter('Content-Type', 'delsp') == 'yes')
? true
: false;
return 'yes' == $this->_getHeaderParameter('Content-Type', 'delsp') ? true : false;
}
/**
@ -196,7 +194,7 @@ class Swift_Mime_MimePart extends Swift_Mime_SimpleMimeEntity
protected function _convertString($string)
{
$charset = strtolower($this->getCharset());
if (!in_array($charset, array('utf-8', 'iso-8859-1', ''))) {
if (!in_array($charset, array('utf-8', 'iso-8859-1', 'iso-8859-15', ''))) {
// mb_convert_encoding must be the first one to check, since iconv cannot convert some words.
if (function_exists('mb_convert_encoding')) {
$string = mb_convert_encoding($string, $charset, 'utf-8');

View file

@ -112,12 +112,7 @@ class Swift_Mime_SimpleHeaderFactory implements Swift_Mime_HeaderFactory
public function createParameterizedHeader($name, $value = null,
$params = array())
{
$header = new Swift_Mime_Headers_ParameterizedHeader($name,
$this->_encoder, (strtolower($name) == 'content-disposition')
? $this->_paramEncoder
: null,
$this->_grammar
);
$header = new Swift_Mime_Headers_ParameterizedHeader($name, $this->_encoder, strtolower($name) == 'content-disposition' ? $this->_paramEncoder : null, $this->_grammar);
if (isset($value)) {
$header->setFieldBodyModel($value);
}

View file

@ -349,12 +349,13 @@ class Swift_Mime_SimpleHeaderSet implements Swift_Mime_HeaderSet
{
$lowerA = strtolower($a);
$lowerB = strtolower($b);
$aPos = array_key_exists($lowerA, $this->_order)
? $this->_order[$lowerA]
: -1;
$bPos = array_key_exists($lowerB, $this->_order)
? $this->_order[$lowerB]
: -1;
$aPos = array_key_exists($lowerA, $this->_order) ? $this->_order[$lowerA] : -1;
$bPos = array_key_exists($lowerB, $this->_order) ? $this->_order[$lowerB] : -1;
if (-1 === $aPos && -1 === $bPos) {
// just be sure to be determinist here
return $a > $b ? -1 : 1;
}
if ($aPos == -1) {
return 1;
@ -362,7 +363,7 @@ class Swift_Mime_SimpleHeaderSet implements Swift_Mime_HeaderSet
return -1;
}
return ($aPos < $bPos) ? -1 : 1;
return $aPos < $bPos ? -1 : 1;
}
/** Test if the given Header is always displayed */

View file

@ -253,7 +253,7 @@ class Swift_Mime_SimpleMessage extends Swift_Mime_MimePart implements Swift_Mime
* If $name is passed and the first parameter is a string, this name will be
* associated with the address.
*
* @param string $addresses
* @param mixed $addresses
* @param string $name optional
*
* @return Swift_Mime_SimpleMessage

View file

@ -282,11 +282,7 @@ class Swift_Mime_SimpleMimeEntity implements Swift_Mime_MimeEntity
{
// TODO: Try to refactor this logic
$compoundLevel = isset($compoundLevel)
? $compoundLevel
: $this->_getCompoundLevel($children)
;
$compoundLevel = isset($compoundLevel) ? $compoundLevel : $this->_getCompoundLevel($children);
$immediateChildren = array();
$grandchildren = array();
$newContentType = $this->_userContentType;
@ -311,15 +307,15 @@ class Swift_Mime_SimpleMimeEntity implements Swift_Mime_MimeEntity
}
}
if (!empty($immediateChildren)) {
if ($immediateChildren) {
$lowestLevel = $this->_getNeededChildLevel($immediateChildren[0], $compoundLevel);
// Determine which composite media type is needed to accommodate the
// immediate children
foreach ($this->_compositeRanges as $mediaType => $range) {
if ($lowestLevel > $range[0]
&& $lowestLevel <= $range[1]) {
if ($lowestLevel > $range[0] && $lowestLevel <= $range[1]) {
$newContentType = $mediaType;
break;
}
}
@ -349,9 +345,7 @@ class Swift_Mime_SimpleMimeEntity implements Swift_Mime_MimeEntity
*/
public function getBody()
{
return ($this->_body instanceof Swift_OutputByteStream)
? $this->_readStream($this->_body)
: $this->_body;
return $this->_body instanceof Swift_OutputByteStream ? $this->_readStream($this->_body) : $this->_body;
}
/**
@ -486,12 +480,8 @@ class Swift_Mime_SimpleMimeEntity implements Swift_Mime_MimeEntity
if ($this->_cache->hasKey($this->_cacheKey, 'body')) {
$body = $this->_cache->getString($this->_cacheKey, 'body');
} else {
$body = "\r\n".$this->_encoder->encodeString($this->getBody(), 0,
$this->getMaxLineLength()
);
$this->_cache->setString($this->_cacheKey, 'body', $body,
Swift_KeyCache::MODE_WRITE
);
$body = "\r\n".$this->_encoder->encodeString($this->getBody(), 0, $this->getMaxLineLength());
$this->_cache->setString($this->_cacheKey, 'body', $body, Swift_KeyCache::MODE_WRITE);
}
$string .= $body;
}
@ -602,9 +592,9 @@ class Swift_Mime_SimpleMimeEntity implements Swift_Mime_MimeEntity
$this->_headers->get($field)->setFieldBodyModel($model);
return true;
} else {
return false;
}
return false;
}
/**
@ -626,9 +616,9 @@ class Swift_Mime_SimpleMimeEntity implements Swift_Mime_MimeEntity
$this->_headers->get($field)->setParameter($parameter, $value);
return true;
} else {
return false;
}
return false;
}
/**
@ -716,9 +706,7 @@ class Swift_Mime_SimpleMimeEntity implements Swift_Mime_MimeEntity
private function _assertValidBoundary($boundary)
{
if (!preg_match(
'/^[a-z0-9\'\(\)\+_\-,\.\/:=\?\ ]{0,69}[a-z0-9\'\(\)\+_\-,\.\/:=\?]$/Di',
$boundary)) {
if (!preg_match('/^[a-z0-9\'\(\)\+_\-,\.\/:=\?\ ]{0,69}[a-z0-9\'\(\)\+_\-,\.\/:=\?]$/Di', $boundary)) {
throw new Swift_RfcComplianceException('Mime boundary set is not RFC 2046 compliant.');
}
}
@ -757,18 +745,16 @@ class Swift_Mime_SimpleMimeEntity implements Swift_Mime_MimeEntity
$realLevel = $child->getNestingLevel();
$lowercaseType = strtolower($child->getContentType());
if (isset($filter[$realLevel])
&& isset($filter[$realLevel][$lowercaseType])) {
if (isset($filter[$realLevel]) && isset($filter[$realLevel][$lowercaseType])) {
return $filter[$realLevel][$lowercaseType];
} else {
return $realLevel;
}
return $realLevel;
}
private function _createChild()
{
return new self($this->_headers->newInstance(),
$this->_encoder, $this->_cache, $this->_grammar);
return new self($this->_headers->newInstance(), $this->_encoder, $this->_cache, $this->_grammar);
}
private function _notifyEncoderChanged(Swift_Mime_ContentEncoder $encoder)
@ -807,17 +793,13 @@ class Swift_Mime_SimpleMimeEntity implements Swift_Mime_MimeEntity
private function _childSortAlgorithm($a, $b)
{
$typePrefs = array();
$types = array(
strtolower($a->getContentType()),
strtolower($b->getContentType()),
);
$types = array(strtolower($a->getContentType()), strtolower($b->getContentType()));
foreach ($types as $type) {
$typePrefs[] = (array_key_exists($type, $this->_alternativePartOrder))
? $this->_alternativePartOrder[$type]
: (max($this->_alternativePartOrder) + 1);
$typePrefs[] = array_key_exists($type, $this->_alternativePartOrder) ? $this->_alternativePartOrder[$type] : max($this->_alternativePartOrder) + 1;
}
return ($typePrefs[0] >= $typePrefs[1]) ? 1 : -1;
return $typePrefs[0] >= $typePrefs[1] ? 1 : -1;
}
// -- Destructor
@ -839,14 +821,8 @@ class Swift_Mime_SimpleMimeEntity implements Swift_Mime_MimeEntity
*/
private function _assertValidId($id)
{
if (!preg_match(
'/^'.$this->_grammar->getDefinition('id-left').'@'.
$this->_grammar->getDefinition('id-right').'$/D',
$id
)) {
throw new Swift_RfcComplianceException(
'Invalid ID given <'.$id.'>'
);
if (!preg_match('/^'.$this->_grammar->getDefinition('id-left').'@'.$this->_grammar->getDefinition('id-right').'$/D', $id)) {
throw new Swift_RfcComplianceException('Invalid ID given <'.$id.'>');
}
}
@ -857,7 +833,7 @@ class Swift_Mime_SimpleMimeEntity implements Swift_Mime_MimeEntity
{
$this->_headers = clone $this->_headers;
$this->_encoder = clone $this->_encoder;
$this->_cacheKey = uniqid();
$this->_cacheKey = md5(uniqid(getmypid().mt_rand(), true));
$children = array();
foreach ($this->_children as $pos => $child) {
$children[$pos] = clone $child;

View file

@ -157,12 +157,9 @@ class Swift_Plugins_DecoratorPlugin implements Swift_Events_SendListener, Swift_
{
if ($this->_replacements instanceof Swift_Plugins_Decorator_Replacements) {
return $this->_replacements->getReplacementsFor($address);
} else {
return isset($this->_replacements[$address])
? $this->_replacements[$address]
: null
;
}
return isset($this->_replacements[$address]) ? $this->_replacements[$address] : null;
}
/**

View file

@ -49,25 +49,13 @@ class Swift_Plugins_ReporterPlugin implements Swift_Events_SendListener
$message = $evt->getMessage();
$failures = array_flip($evt->getFailedRecipients());
foreach ((array) $message->getTo() as $address => $null) {
$this->_reporter->notify(
$message, $address, (array_key_exists($address, $failures)
? Swift_Plugins_Reporter::RESULT_FAIL
: Swift_Plugins_Reporter::RESULT_PASS)
);
$this->_reporter->notify($message, $address, array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS);
}
foreach ((array) $message->getCc() as $address => $null) {
$this->_reporter->notify(
$message, $address, (array_key_exists($address, $failures)
? Swift_Plugins_Reporter::RESULT_FAIL
: Swift_Plugins_Reporter::RESULT_PASS)
);
$this->_reporter->notify($message, $address, array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS);
}
foreach ((array) $message->getBcc() as $address => $null) {
$this->_reporter->notify(
$message, $address, (array_key_exists($address, $failures)
? Swift_Plugins_Reporter::RESULT_FAIL
: Swift_Plugins_Reporter::RESULT_PASS)
);
$this->_reporter->notify($message, $address, array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS);
}
}
}

View file

@ -151,9 +151,9 @@ class Swift_Plugins_ThrottlerPlugin extends Swift_Plugins_BandwidthMonitorPlugin
{
if (isset($this->_timer)) {
return $this->_timer->getTimestamp();
} else {
return time();
}
return time();
}
/**

View file

@ -62,12 +62,12 @@ class Swift_Signers_DKIMSigner implements Swift_Signers_HeaderSigner
*
* @var array
*/
protected $_ignoredHeaders = array();
protected $_ignoredHeaders = array('return-path' => true);
/**
* Signer identity.
*
* @var unknown_type
* @var string
*/
protected $_signerIdentity;
@ -143,13 +143,6 @@ class Swift_Signers_DKIMSigner implements Swift_Signers_HeaderSigner
*/
protected $_dkimHeader;
/**
* Hash Handler.
*
* @var hash_ressource
*/
private $_headerHashHandler;
private $_bodyHashHandler;
private $_headerHash;
@ -206,7 +199,6 @@ class Swift_Signers_DKIMSigner implements Swift_Signers_HeaderSigner
{
$this->_headerHash = null;
$this->_signedHeaders = array();
$this->_headerHashHandler = null;
$this->_bodyHash = null;
$this->_bodyHashHandler = null;
$this->_bodyCanonIgnoreStart = 2;
@ -381,7 +373,7 @@ class Swift_Signers_DKIMSigner implements Swift_Signers_HeaderSigner
$this->_showLen = true;
$this->_maxLen = PHP_INT_MAX;
} elseif ($len === false) {
$this->showLen = false;
$this->_showLen = false;
$this->_maxLen = PHP_INT_MAX;
} else {
$this->_showLen = true;
@ -394,7 +386,7 @@ class Swift_Signers_DKIMSigner implements Swift_Signers_HeaderSigner
/**
* Set the signature timestamp.
*
* @param timestamp $time
* @param int $time A timestamp
*
* @return Swift_Signers_DKIMSigner
*/
@ -408,7 +400,7 @@ class Swift_Signers_DKIMSigner implements Swift_Signers_HeaderSigner
/**
* Set the signature expiration timestamp.
*
* @param timestamp $time
* @param int $time A timestamp
*
* @return Swift_Signers_DKIMSigner
*/
@ -588,9 +580,13 @@ class Swift_Signers_DKIMSigner implements Swift_Signers_HeaderSigner
$this->_addToHeaderHash($header);
}
/**
* @deprecated This method is currently useless in this class but it must be
* kept for BC reasons due to its "protected" scope. This method
* might be overriden by custom client code.
*/
protected function _endOfHeaders()
{
//$this->_headerHash=hash_final($this->_headerHashHandler, true);
}
protected function _canonicalizeBody($string)

Some files were not shown because too many files have changed in this diff Show more