diff --git a/.buildpath b/.buildpath new file mode 100644 index 0000000..58a40b7 --- /dev/null +++ b/.buildpath @@ -0,0 +1,219 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore index a67d42b..52b47ef 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ composer.phar # Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file # composer.lock +/composer.lock +/set-local-test-env.sh diff --git a/.project b/.project new file mode 100644 index 0000000..51153c6 --- /dev/null +++ b/.project @@ -0,0 +1,33 @@ + + + php-email + + + + + + org.eclipse.php.composer.core.builder.buildPathManagementBuilder + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + org.eclipse.wst.validation.validationbuilder + + + + + org.eclipse.dltk.core.scriptbuilder + + + + + + org.eclipse.php.core.PHPNature + org.eclipse.wst.common.project.facet.core.nature + + diff --git a/.settings/org.eclipse.php.composer.core.prefs b/.settings/org.eclipse.php.composer.core.prefs new file mode 100644 index 0000000..c350800 --- /dev/null +++ b/.settings/org.eclipse.php.composer.core.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +include_path=0;/php-email/src +org.eclipse.php.composer.corebuildpath.includes.excludes=\n diff --git a/.settings/org.eclipse.php.core.prefs b/.settings/org.eclipse.php.core.prefs new file mode 100644 index 0000000..5daaa54 --- /dev/null +++ b/.settings/org.eclipse.php.core.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +include_path=0;/php-email/src diff --git a/.settings/org.eclipse.php.ui.prefs b/.settings/org.eclipse.php.ui.prefs new file mode 100644 index 0000000..9a3362f --- /dev/null +++ b/.settings/org.eclipse.php.ui.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +org.eclipse.php.ui.text.custom_code_templates= diff --git a/.settings/org.eclipse.wst.common.project.facet.core.xml b/.settings/org.eclipse.wst.common.project.facet.core.xml new file mode 100644 index 0000000..54838ab --- /dev/null +++ b/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/.settings/org.eclipse.wst.validation.prefs b/.settings/org.eclipse.wst.validation.prefs new file mode 100644 index 0000000..39a5ef6 --- /dev/null +++ b/.settings/org.eclipse.wst.validation.prefs @@ -0,0 +1,2 @@ +disabled=06vendor +eclipse.preferences.version=1 diff --git a/README.md b/README.md index 0f4aa98..4549c15 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,388 @@ # php-email -Provides an object-oriented way to send and queue emails +Provides an object-oriented way to send and queue emails. + +There is a need to send e-mails in almost all projects, e.g. for user registration or +password reset functions. Most e-mails sent are very easy. Sophisticated features +like PGP encryption etc is not required. This library offers a way to create +such e-mails without setting up the PHPMailer (the underlying library), to send +multiple e-mails and even to defer sending e-mail sending by using a queue backed +by a database - and all in an object-oriented way. + +Features are: + +* Encapsulating SMTP settings in an `EmailQueue` object. +* Reuse a mailer object for multiple e-mails +* Sending HTML and TEXT e-mails +* Embedding pictures and attaching files +* Enqueueing mails in a database backend +* Prefixing subject lines automatically +* Easily create compatible e-mail addresses including the address name +* E-mail queue will try to send an e-mail multiple times before failing +* Ability to set a "Mail Mode". Mail Modes can BCC, reroute or even block e-mails completely + which can be useful in development or acceptance environments. + +# License +This project is licensed under [GNU LGPL 3.0](LICENSE.md). + +# Installation + +## By Composer + +``` +composer install technicalguru/email +``` + +## By Package Download +You can download the source code packages from [GitHub Release Page](https://github.com/technicalguru/php-email/releases) + +# How to use it + +## Create Main Configuration Object + +The central class for configuration is the `EmailConfig`. It holds all necessary information. +Let's start with the basic skeleton: + +``` + +use TgEmail\EmailConfig; + +$config = new EmailConfig(); +$config->setTimezone('Europe/Berlin'); +$config->setDefaultSender('John Doe '); +$config->setSubjectPrefix('[MyAppName] '); +$config->setDebugAddress('admin@example.com'); +``` + +The lines above create the configuration and tells it to use the timezone `Europe/Berlin` when it needs +to create timestamps. This is required mainly when e-mails are queued and the timestamp needs to be +recorded. This value is optional and defaults to `UTC`. + +Next, a default sender address is configured. The default sender will be used when a specific +e-mail to be sent does not define a sender address. Creating e-mail addresses is explained further below. + +The subject prefix is used on every e-mail to be sent later. Subjects will be prefixed with this string. The +default is `NULL` and will not modify the subject. + +A debug address is required only when you need to send a test mail. + +## Create SMTP Configuration + +We still need to tell where our SMTP server is located. So this is how you set these values: + +``` +use TgEmail\Config\SmtpConfig; + +$host = 'smtp.example.com; +$port = 587; +$auth = TRUE; +$username = 'mySmtpUser'; +$password = 'mySmtpPassword'; +$secureOption = 'starttls'; + +$smtpConfig = new SmtpConfig($host, $port, $auth, $username, $password, $secureOption); +$config->setSmtpConfig($smtpConfig); +``` + +Most options are self-explaining. `$auth` tells underlying PHPMailer whether to authenticate with given +user credentials. `$secureOption` is defined by `PHPMailer` and shall have value `smtps` or `starttls`. +See the PHPMailer documentation for further information. + +All properties can be set by using a setter: + +``` +use TgEmail\Config\SmtpConfig; + +$smtpConfig = new SmtpConfig(); +$smtpConfig->setHost('smtp.example.com'); +$smtpConfig->setPort(587); + +// continue setup... +``` + +Authentication credentials can also be set by using the `\TgUtils\Auth\CredentialsProvider` interface from +`technicalguru/utils` package: + +``` +// Define here your provider +$provider = ...; + +// Tell SMTP config +$smtpConfig->setCredentialsProvider($provider); +``` + +## Create the Main MailQueue object + +Now it's time to create our central `MailQueue` object: + +``` +use TgEmail\EmailQueue; + +$mailer = new EmailQueue($config); +``` + +You are ready send your first e-mail. + +## Send a Test E-Mail + +There is a fast and easy way to check whether your setup works correctly: + +``` +$email = $mailer->createTestMail(); +$rc = $mailer->send($email); +``` + +## Send an E-Mail + +We have setup the minimum requirements to send an e-mail: + +``` +use TgEmail\Email; + +$email = new Email(); +$email + ->setSubject('Hello World') + ->addTo('john.doe@example.com', 'John Doe') + ->addBcc('jane.doe@example.com') + ->setReplyTo('my-support@example.com') + ->setBody(Email::TEXT, 'The text e-mail body') + ->setBody(Email::HTML, '

The HTML e-mail body

'); + +// Will return FALSE when sending fails +$rc = $mailer->send($email); +``` + +That's it. The code snippet above is all you would need in your application code in order to send e-mails. +Configuration and setup shall be buried somewhere in your infrastructure setup. + +## Hot to add Attachments or embed Images + +Attaching files or embedding images is simple. You will need to have the file available and readable +on the filesystem: + +``` +use TgEmail\Attachment; + +$myFile = new Attachment(Attachment::ATTACHED, 'file.pdf', NULL, '/local/path/to/file.pdf', 'application/pdf'); +$myImage = new Attachment(Attachment::EMBEDDED, 'img.png', 'img1', '/local/path/to/img.png', 'image/png'); + +$email + ->addAttachment($myFile) + ->addAttachment($myImage); +``` + +Note the third parameter of embedded images. It defines a unique ID within your HTML email which you can reference by + +``` +// Using the embedded image +$myHTML = ''; +``` + +The `MailQueue` will leave all your attachments untouched on your filesystem. However, sometimes you may wish to get rid +of the file after you sent the e-mail. The constructor takes two additional arguments: + +``` +$myFile = new Attachment(Attachment::ATTACHED, $filename, $cid, $path, $mimeType, TRUE, TRUE); +``` + +The first boolean will trigger the file to be deleted after the e-mail was sent successfully. The second boolean tells +whether the file can be deleted when sending failed. Using these parameters you don't need to take care +about temporary files anymore. Especially when it comes to queueing and deferred sending. + +## Mail Modes + +`MailQueue` supports so-called Mail Modes. They tell the mailer object how to generally treat e-mails. This comes +comfortable when you're either testing a setup, when you are in an environment that has real e-mail addresses (such as User Acceptance Test environments) or when actually sending out e-mails doesn't make much sense. + +These modes are available: + +* `EmailQueue::DEFAULT` - This is the normal operation. All e-mails are sent as defined. +* `EmailQueue::BLOCK` - This will prevent any mail to be sent or queued. The return code is always TRUE. +* `EmailQueue::REROUTE` - All e-mails will be sent to another address, usually an admin or developer address and the + defined recipients of the e-mail are ignored. +* `EmailQueue::BCC` - The e-mails will be sent to their intended recipients but additional addresses are set on BCC. + +### Blocking all E-Mails + +Blocking all e-mails to be sent or queued is quite easy: + +``` +$mailer->setMailMode(EmailQueue::BLOCK); +``` + +The same method can be used on the central `EmailConfig` object. + +### Rerouting all E-Mails + +You need a `RerouteConfig` configuration to be set in the main configuration. You can set this up-front when creating the +config object, or alltogether when setting the mail mode: + +``` +use TgEmail\Config\RerouteConfig; + +// Create the config +$subjectPrefix = '[Rerouted]'; +$recipients = array('my-dev-account@example.com'); +$rerouteConfig = new RerouteConfig($subjectPrefix, $recipients); + +// And set the mail mode +$mailer->setMailMode(EmailQueue::REROUTE, $rerouteConfig); +``` + +### Set a Developer as BCC on all sent E-mails + +You need a `BccConfig` configuration to be set in the main configuration. You can set this up-front when creating the +config object, or alltogether when setting the mail mode: + +``` +use TgEmail\Config\BccConfig; + +// Create the config +$recipients = array('my-dev-account@example.com'); +$bccConfig = new BccConfig($recipients); + +// And set the mail mode +$mailer->setMailMode(EmailQueue::BCC, $bccConfig); +``` + +## Queue E-Mails to be sent later + +One drawback of sending out e-mails directly from application code is the that it is time-consuming. Your +user needs to wait for the sending to complete before she/he can see any response from your application. +Queueing e-mails is the solution as sending is deferred (preferrable to a cron job) and the user receives +her/his application response fast. + +You will need a [`TgDatabase\Database`](https://github.com/technicalguru/php-database/blob/main/src/TgDatabase/Database.php) +object to queue e-mails. Otherwise, `EmailQueue` will throw exceptions when you try to queue e-mails. Please refer +to the [`TgDatabase\Database`](https://github.com/technicalguru/php-database/) documentation about how to create +the `Database` object. Setup the according `EmailsDAO` and `EmailQueue` as follows: + +``` +use TgEmail\EmailsDAO; + +$dao = new EmailsDAO($database); +$mailer = new EmailQueue($config, $dao); +``` + +The mailer will automatically create the queue table if it does not exist. + +Once, the `EmailsDAO` is available, you can easily queue e-mails: + +``` +// Create your email object here +$email = ... + +// Queue it. Will return FALSE when sending fails +$rc = $mailer->queue($email); +``` + +## Processing the E-Mail Queue + +You can process the queue in another call or during a cronjob: + +``` +$mailer->processQueue($maxSeconds); +``` + +The argument `$maxSeconds` will ensure that the processing stops when the time limit has been reached. +The argument is optional and defaults to 60 seconds. + +## How to Create an E-mail Address + +There are multiple ways to create e-mail addresses. All mailing components use an `EmailAddress` object. +You can use this object as an argument whereever e-mail addresses are expected. Several ways exist +to create such an object. + +``` +// From a string +$address = EmailAddress::from('john.doe@example.com'); +$address = EmailAddress::from(''); +$address = EmailAddress::from('John Doe '); + +// From email string and name +$address = EmailAddress::from('john.doe@example.com', 'John Doe'); + +// From another object +$obj = new \stdClass; +$obj->name = 'John Doe'; +$obj->email = 'john.doe@example.com'; +$address = EmailAddress::from($obj); + +// From another EmailAddress +$address = EmailAddress::from($anotherEmailAddressObject); +``` + +This means that you can use these flavours when creating e-mails: + +``` +$email->addTo('John Doe '); +$email->addTo('john.doe@example.com', 'John Doe'); +$email->addTo(array('John Doe ', $anotherEmailAddressObject, $obj); +``` + +## Creating Configuration Objects from Objects, Arrays or JSON strings + +The configuration objects introduced above can also be created using JSON strings, objects or associative arrays. +The following snippets describe the JSON objects in short notation. + +``` +SmtpConfig: +----------- +{ + "host": "www.example.com", + "port": 587, + "debugLevel": 0, + "auth": true, + "secureOption": "starttls", + "charset": "utf8", + "credentials": { + "user": "username", + "pass": "password" + } +}, + +RerouteConfig: +-------------- +{ + "recipients": "hans.mustermann@example.com", + "subjectPrefix": "[Rerouted]" +}, + +BccConfig: +---------- +{ + "recipients": "hans.mustermann@example.com" +}, + +EmailConfig: +------------ +{ + "timezone": "Europe\/Berlin", + "mailMode": "default", + "smtpConfig": {... see above ...}, + "rerouteConfig": {... see above ...}, + "bccConfig": {... see above ...}, + "debugAddress": "john.doe@example.com", + "defaultSender": "jane.doe@example.com", + "subjectPrefix": "[PHPUnitTest] " +} +``` + +Each of the configuration classes provide a static `from()` method that take these types as an argument and return the +configuration object itself: + +``` +$smtpConfig = SmtpConfig::from($jsonStringOrObjectOrAssocArray); +$rerouteConfig = RerouteConfig::from($jsonStringOrObjectOrAssocArray); +$bccConfig = BccConfig::from($jsonStringOrObjectOrAssocArray); +$emailConfig = EmailConfig::from($jsonStringOrObjectOrAssocArray); +``` + +# Development Notes + +Most PHPUnit tests will not be executed when there is no SMTP server or database available. The unit tests will check +for environment variable `EMAIL_TEST_SMTP` and `EMAIL_DATABASE`. There is a bash script available, +[`set-test-env.sh`](https://github.com/technicalguru/php-email/blob/main/set-test-env.sh) that creates those +variables for you. Copy it to e.g. `set-local-test-env.sh` and follow instructions in the file. + +# Contribution +Report a bug, request an enhancement or pull request at the [GitHub Issue Tracker](https://github.com/technicalguru/php-email/issues). diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..b5230cc --- /dev/null +++ b/composer.json @@ -0,0 +1,36 @@ +{ + "name" : "technicalguru/email", + "description" : "Provides an object-oriented way to send and queue emails", + "type" : "library", + "keywords" : [ + "email", + "mail", + "mailqueue", + "queue" + ], + "license" : "LGPL-3.0-or-later", + "authors" : [{ + "name" : "technicalguru", + "email" : "github@ralph-schuster.eu" + } + ], + "require" : { + "php" : ">=7.0.0", + "technicalguru/utils" : "~1", + "phpmailer/phpmailer" : "^6.1", + "symfony/polyfill-mbstring" : "^1.20", + "technicalguru/database" : "~0", + "phpunit/phpunit": "^9.4" + }, + "autoload" : { + "psr-4" : { + "TgEmail\\" : "src/TgEmail/", + "" : "" + }, + "psr-0" : { + "TgEmail" : "src/TgEmail" + } + }, + "require-dev" : { + } +} diff --git a/set-test-env.sh b/set-test-env.sh new file mode 100755 index 0000000..12f772d --- /dev/null +++ b/set-test-env.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +####################################################### +# +# TEST HOWTO +# +# Copy this file to e.g. set-local-test-env.sh and +# set the various variables below. Then source the +# file on you bash shell: +# +# ~/git/php-email$ . ./set-local-test-env.sh +# +# and start the PHP Unit tests: +# +# ~/git/php-email$ ./vendor/bin/phpunit tests +# +####################################################### + +# Set this to 2 if your tests fail (will show SMTP debug) +DEBUG_LEVEL=0 + +# Timezone for dates +TIMEZONE="Europe\\/Berlin" + +# The email address that all test emails shall be sent to +TARGET_EMAIL=john.doe@example.com + +# The default sender address +SENDER_EMAIL=jane.doe@example.com + +# The SMTP information +SMTP_HOST=www.example.com +SMTP_PORT=587 +SMTP_AUTH=true +SMTP_USER=username +SMTP_PASS=password +SMTP_SECURE=starttls + +# The Debug Address (for test mail feature +DEBUG_EMAIL=$TARGET_EMAIL + +# The BCC email address (BCC mail mode) +BCC_EMAIL=hans.mustermann@example.com + +# The Reroute email address (REROUTE mail mode) +REROUTE_EMAIL=$BCC_EMAIL + +# The database information +DB_HOST=localhost +DB_PORT=3306 +DB_NAME=databasename +DB_USER=username +DB_PASS=password +DB_PREFIX=phpunittest_ + +################ DO NOT EDIT FROM HERE ON ############# +BCC_CONFIG="{\"recipients\":\"${BCC_EMAIL}\"}" +REROUTE_CONFIG="{\"recipients\":\"${REROUTE_EMAIL}\",\"subjectPrefix\":\"[Rerouted]\"}" + +SMTP_CONFIG="{\"host\":\"${SMTP_HOST}\",\"port\":${SMTP_PORT},\"debugLevel\":${DEBUG_LEVEL},\"auth\":${SMTP_AUTH},\"credentials\":{\"user\":\"${SMTP_USER}\",\"pass\":\"${SMTP_PASS}\"},\"secureOption\":\"${SMTP_SECURE}\",\"charset\":\"utf8\"}" + +EMAIL_TEST_SMTP="{\"timezone\":\"${TIMEZONE}\",\"mailMode\":\"default\",\"targetAddress\":\"${TARGET_EMAIL}\", \"smtpConfig\":${SMTP_CONFIG},\"rerouteConfig\":${REROUTE_CONFIG},\"bccConfig\":${BCC_CONFIG},\"debugAddress\":\"${DEBUG_EMAIL}\",\"defaultSender\":\"${SENDER_EMAIL}\",\"subjectPrefix\":\"[PHPUnitTest] \"}" +EMAIL_DATABASE="{\"host\":\"${DB_HOST}\",\"port\":${DB_PORT},\"dbname\":\"${DB_NAME}\",\"user\":\"${DB_USER}\",\"pass\":\"${DB_PASS}\",\"tablePrefix\":\"${DB_PREFIX}\"}" + +export EMAIL_TEST_SMTP +export EMAIL_DATABASE + + + + diff --git a/src/TgEmail/Attachment.php b/src/TgEmail/Attachment.php new file mode 100644 index 0000000..c91db4b --- /dev/null +++ b/src/TgEmail/Attachment.php @@ -0,0 +1,52 @@ +The actual content of the attachment must be available as a file. + * @author ralph + * + */ +class Attachment { + + public const ATTACHED = 'default'; + public const EMBEDDED = 'embedded'; + + /** The embedding type */ + public $type; + public $name; + public $cid; + public $path; + public $mimeType; + public $deleteAfterSent; + public $deleteAfterFailed; + + /** + * Constructor. + * @param string $type - the embedding type of this attachment + * @param string $name - the name of the attachment as to be used in email + * @param string $path - the path to the local file + * @param boolean deleteAfterSent - whether to delete the file when the mail was sent + * @param boolean deleteAfterFailed - whether to delete the file when sending of the email failed (requires deleteAfterSent = TRUE) + */ + public function __construct($type, $name, $cid, $path, $mimeType, $deleteAfterSent = false, $deleteAfterFailed = false) { + $this->type = $type; + $this->name = $name; + $this->cid = $cid; + $this->path = $path; + $this->deleteAfterSent = $deleteAfterSent; + $this->deleteAfterFailed = $deleteAfterFailed; + } + + public static function from($a) { + if (is_object($a)) { + if (is_a($a, 'TgEmail\\Attachment')) { + return $a; + } + return new Attachment($a->type, $a->name, $a->cid, $a->path, $a->mimeType, $a->deleteAfterSent, $a->deleteAfterFailed); + } + throw new EmailException('Cannot convert attachment'); + } +} + diff --git a/src/TgEmail/Config/BccConfig.php b/src/TgEmail/Config/BccConfig.php new file mode 100644 index 0000000..e5a9f44 --- /dev/null +++ b/src/TgEmail/Config/BccConfig.php @@ -0,0 +1,61 @@ +recipients = array(); + $this->addRecipients($recipients); + } + + public function getRecipients() { + return $this->recipients; + } + + public function addRecipients($address, $name = NULL) { + if (is_array($address)) { + foreach ($address AS $a) { + $this->addRecipients($a); + } + } else if (is_string($address)) { + $this->recipients[] = EmailAddress::from($address, $name); + } else if (is_object($address)) { + $this->recipients[] = EmailAddress::from($address); + } else { + throw new EmailException('Cannot add recipient(s)'); + } + return $this; + } + + public static function from($config) { + if (is_array($config)) { + $config = json_decode(json_encode($config)); + } else if (is_string($config)) { + $config = json_decode($config); + } + if (is_object($config)) { + $rc = new BccConfig(); + if (isset($config->recipients)) { + $rc->addRecipients($config->recipients); + } + return $rc; + } + throw new EmailException('Cannot create BccConfig object from given config'); + } + +} + diff --git a/src/TgEmail/Config/RerouteConfig.php b/src/TgEmail/Config/RerouteConfig.php new file mode 100644 index 0000000..496df5c --- /dev/null +++ b/src/TgEmail/Config/RerouteConfig.php @@ -0,0 +1,74 @@ +subjectPrefix = $subjectPrefix; + $this->recipients = array(); + $this->addRecipients($recipients); + } + + public function getSubjectPrefix() { + return $this->subjectPrefix; + } + + public function setSubjectPrefix($prefix) { + $this->subjectPrefix = $prefix; + } + + public function getRecipients() { + return $this->recipients; + } + + public function addRecipients($address, $name = NULL) { + if (is_array($address)) { + foreach ($address AS $a) { + $this->addRecipients($a); + } + } else if (is_string($address)) { + $this->recipients[] = EmailAddress::from($address, $name); + } else if (is_object($address)) { + $this->recipients[] = EmailAddress::from($address); + } else { + throw new EmailException('Cannot add recipient(s)'); + } + return $this; + } + + public static function from($config) { + if (is_array($config)) { + $config = json_decode(json_encode($config)); + } else if (is_string($config)) { + $config = json_decode($config); + } + if (is_object($config)) { + $rc = new RerouteConfig(); + if (isset($config->recipients)) { + $rc->addRecipients($config->recipients); + } + if (isset($config->subjectPrefix)) { + $rc->setSubjectPrefix($config->subjectPrefix); + } + return $rc; + } + throw new EmailException('Cannot create RerouteConfig object from given config'); + } + +} + diff --git a/src/TgEmail/Config/SmtpConfig.php b/src/TgEmail/Config/SmtpConfig.php new file mode 100644 index 0000000..23d4a1d --- /dev/null +++ b/src/TgEmail/Config/SmtpConfig.php @@ -0,0 +1,189 @@ +host = $host; + $this->port = $port; + $this->auth = $auth; + $this->setCredentials($username, $password); + $this->secureOption = $secureOption; + $this->charset = $charset; + } + + public function getHost() { + return $this->host; + } + + public function setHost($host) { + $this->host = $host; + return $this; + } + + public function getPort() { + return $this->port; + } + + public function setPort($port) { + $this->port = $port; + return $this; + } + + public function getDebugLevel() { + return $this->debugLevel; + } + + public function setDebugLevel($level) { + $this->debugLevel = $level; + return $this; + } + + public function isAuth() { + return $this->auth; + } + + public function setAuth($auth) { + $this->auth = $auth; + return $this; + } + + public function getSecureOption() { + return $this->secureOption; + } + + public function setSecureOption($option) { + $this->secureOption = $option; + return $this; + } + + public function getUsername() { + return $this->getCredentialsProvider()->getUsername(); + } + + public function getPassword() { + return $this->getCredentialsProvider()->getPassword(); + } + + public function setCredentials($username, $password) { + $this->setCredentialsProvider(new DefaultCredentialsProvider($username, $password)); + return $this; + } + + public function getCredentialsProvider() { + return $this->credentialsProvider; + } + + public function setCredentialsProvider(CredentialsProvider $provider) { + $this->credentialsProvider = $provider; + return $this; + } + + public function getCharset() { + return $this->charset; + } + + public function setCharset($charset) { + $this->charset = $charset; + return $this; + } + + public static function from($config) { + if (is_array($config)) { + $config = json_decode(json_encode($config)); + } else if (is_string($config)) { + $config = json_decode($config); + } + if (is_object($config)) { + $rc = new SmtpConfig(); + if (isset($config->host)) { + $rc->setHost($config->host); + } + if (isset($config->port)) { + $rc->setPort($config->port); + } + if (isset($config->debugLevel)) { + $rc->setDebugLevel($config->debugLevel); + } + if (isset($config->auth)) { + $rc->setAuth($config->auth); + } + if (isset($config->credentialsProvider)) { + if (is_a($config->credentialsProvider, 'TgUtils\Auth\CredentialsProvider')) { + $rc->setCredentialsProvider($config->credentialsProvider); + } else if (is_object($config->credentialsProvider)) { + $username = NULL; + $password = NULL; + if (isset($config->credentialsProvider->username)) { + $username = $config->credentialsProvider->username; + } + if (isset($config->credentialsProvider->user)) { + $username = $config->credentialsProvider->user; + } + if (isset($config->credentialsProvider->password)) { + $password = $config->credentialsProvider->password; + } + if (isset($config->credentialsProvider->passwd)) { + $password = $config->credentialsProvider->passwd; + } + if (isset($config->credentialsProvider->pass)) { + $password = $config->credentialsProvider->pass; + } + $rc->setCredentials($username, $password); + } else { + throw new EmailException('Cannot configure credentialsProvider from given config'); + } + } else if (isset($config->credentials)) { + $username = NULL; + $password = NULL; + if (isset($config->credentials->username)) { + $username = $config->credentials->username; + } + if (isset($config->credentials->user)) { + $username = $config->credentials->user; + } + if (isset($config->credentials->password)) { + $password = $config->credentials->password; + } + if (isset($config->credentials->passwd)) { + $password = $config->credentials->passwd; + } + if (isset($config->credentials->pass)) { + $password = $config->credentials->pass; + } + $rc->setCredentials($username, $password); + } + if (isset($config->secureOption)) { + $rc->setSecureOption($config->secureOption); + } + if (isset($config->charset)) { + $rc->setCharset($config->charset); + } + return $rc; + } + throw new EmailException('Cannot create SmtpConfig object from given config'); + } + +} + diff --git a/src/TgEmail/Email.php b/src/TgEmail/Email.php new file mode 100644 index 0000000..d641e1a --- /dev/null +++ b/src/TgEmail/Email.php @@ -0,0 +1,236 @@ +sender != NULL) { + if (!is_object($this->sender)) { + $this->sender = EmailAddress::from($this->sender); + } + } + return $this->sender; + } + + public function setSender($email, $name = NULL) { + $this->sender = EmailAddress::from($email, $name); + return $this; + } + + public function getReplyTo() { + if ($this->reply_to != NULL) { + if (!is_object($this->reply_to)) { + $this->reply_to = EmailAddress::from($this->reply_to); + } + } + return $this->reply_to; + } + + public function setReplyTo($email, $name = NULL) { + $this->reply_to = EmailAddress::from($email, $name); + return $this; + } + + protected function getRecipients() { + if ($this->recipients == NULL) { + $this->recipients = new \stdClass; + $this->recipients->to = array(); + $this->recipients->cc = array(); + $this->recipients->bcc = array(); + } + if (!is_object($this->recipients)) { + $this->recipients = json_decode($this->recipients); + $this->recipients->to = $this->convertToAddresses($this->recipients->to); + $this->recipients->cc = $this->convertToAddresses($this->recipients->cc); + $this->recipients->bcc = $this->convertToAddresses($this->recipients->bcc); + } + return $this->recipients; + } + + protected function convertToAddresses($arr) { + $rc = array(); + foreach ($arr AS $address) { + $rc[] = EmailAddress::from($address); + } + return $rc; + } + + public function getTo() { + return $this->getRecipients()->to; + } + + public function addTo($address, $name = NULL) { + if (is_array($address)) { + foreach ($address AS $a) { + $this->addTo($a); + } + } else if (is_string($address)) { + $this->getRecipients()->to[] = EmailAddress::from($address, $name); + } else if (is_object($address)) { + $this->getRecipients()->to[] = EmailAddress::from($address); + } else { + throw new EmailException('Cannot add TO recipient(s)'); + } + return $this; + } + + public function getCc() { + return $this->getRecipients()->cc; + } + + public function addCc($address, $name = NULL) { + if (is_array($address)) { + foreach ($address AS $a) { + $this->addCc($a); + } + } else if (is_string($address)) { + $this->getRecipients()->cc[] = EmailAddress::from($address, $name); + } else if (is_object($address)) { + $this->getRecipients()->cc[] = EmailAddress::from($address); + } else { + throw new EmailException('Cannot add CC recipient(s)'); + } + return $this; + } + + public function getBcc() { + return $this->getRecipients()->bcc; + } + + public function addBcc($address, $name = NULL) { + if (is_array($address)) { + foreach ($address AS $a) { + $this->addBcc($a); + } + } else if (is_string($address)) { + $this->getRecipients()->bcc[] = EmailAddress::from($address, $name); + } else if (is_object($address)) { + $this->getRecipients()->bcc[] = EmailAddress::from($address); + } else { + throw new EmailException('Cannot add BCC recipient(s)'); + } + return $this; + } + + public function getSubject() { + return $this->subject; + } + + public function setSubject($s) { + $this->subject = $s; + return $this; + } + + public function getBody($type = 'text') { + if (($this->body != NULL) && is_string($this->body)) { + $this->body = json_decode($this->body); + } else if ($this->body == NULL) { + $this->body = new \stdClass; + } + if (isset($this->body->$type)) { + return $this->body->$type; + } + return NULL; + } + + public function setBody($type = 'text', $body) { + if (($this->body != NULL) && is_string($this->body)) { + $this->body = json_decode($this->body); + } else if ($this->body == NULL) { + $this->body = new \stdClass; + } + $this->body->$type = $body; + return $this; + } + + public function getAttachments() { + if ($this->attachments == NULL) { + $this->attachments = array(); + } else if (is_string($this->attachments)) { + $arr = json_decode($this->attachments); + $this->attachments = array(); + foreach ($arr AS $a) { + $this->attachments[] = Attachment::from($a); + } + } + return $this->attachments; + } + + public function addAttachment(Attachment $a) { + $this->getAttachments(); + $this->attachments[] = $a; + return $this; + } + + public function addAttachments(array $arr) { + $this->getAttachments(); + foreach ($arr AS $a) { + $this->attachments[] = $a; + } + return $this; + } + + public function getSentTime($timezone = 'UTC') { + if (($this->sent_time != NULL) && is_string($this->sent_time)) { + $this->sent_time = new Date($this->sent_time, $timezone); + } + return $this->sent_time; + } + + public function getQueuedTime($timezone = 'UTC') { + if (($this->queued_time != NULL) && is_string($this->queued_time)) { + $this->queued_time = new Date($this->queued_time, $timezone); + } + return $this->queued_time; + } + + public function getLogString() { + $rc = 'TO='.$this->stringify($this->getRecipients()->to); + $rc .= ' CC='.$this->stringify($this->getRecipients()->cc); + $rc .= ' BCC='.$this->stringify($this->getRecipients()->bcc); + return $rc; + } + + public function stringify($addresses) { + $rc = array(); + foreach ($addresses AS $a) { + $rc[] = $a->__toString(); + } + return implode(',', $rc); + } +} + diff --git a/src/TgEmail/EmailAddress.php b/src/TgEmail/EmailAddress.php new file mode 100644 index 0000000..113bc2b --- /dev/null +++ b/src/TgEmail/EmailAddress.php @@ -0,0 +1,82 @@ +email = $email; + $this->name = $name; + } + + /** + * Returns the mail-compliant address string. + * + * @return string the address string. + */ + public function __toString() { + if ($this->name != NULL) { + return $this->name . ' <' . $this->email . '>'; + } + return '<' . $this->email . '>'; + } + + /** + * Returns a EmailAddress object from a compliant string. + * + * @param string $s + * - a mail compliant string + * @return EmailAddress - The EmailAddress object + */ + public static function from($s, $name = NULL) { + if (is_string($s)) { + if ($name == NULL) { + $pos = strpos($s, '<'); + if ($pos !== FALSE) { + $name = $pos > 0 ? trim(substr($s, 0, $pos)) : NULL; + if ($name == '') $name = NULL; + + $email = substr($s, $pos + 1); + $pos = strpos($email, '>'); + if ($pos !== FALSE) { + $email = trim(substr($email, 0, $pos)); + } + + return new EmailAddress($email, $name); + } + return new EmailAddress($s); + } else { + return new EmailAddress($s, $name); + } + } else if (is_a($s, 'TgEmail\\EmailAddress')) { + return $s; + } else if (is_object($s)) { + return new EmailAddress($s->email, $s->name); + } + } +} + diff --git a/src/TgEmail/EmailConfig.php b/src/TgEmail/EmailConfig.php new file mode 100644 index 0000000..24dc5c6 --- /dev/null +++ b/src/TgEmail/EmailConfig.php @@ -0,0 +1,183 @@ +timezone = 'UTC'; + $this->mailMode = EmailQueue::DEFAULT; + $this->setSmtpConfig($smtpConfig); + $this->setRerouteConfig($rerouteConfig); + $this->setBccConfig($bccConfig); + $this->debugAddress = array(); + $this->defaultSender = NULL; + $this->subjectPrefix = NULL; + } + + public function getTimezone() { + return $this->timezone; + } + + public function setTimezone($tz) { + $this->timezone = $tz; + return $this; + } + + public function getMailMode() { + return $this->mailMode; + } + + public function setMailMode($mailMode, $config = NULL) { + if ($mailMode == EmailQueue::REROUTE) { + if ($config != NULL) { + $this->setRerouteConfig($config); + } + if ($this->getRerouteConfig() == NULL) { + throw new EmailException('No RerouteConfig available. Set the config along with the mailMode.'); + } + } else if ($mailMode == EmailQueue::BCC) { + if ($config != NULL) { + $this->setBccConfig($config); + } + if ($this->getBccConfig() == NULL) { + throw new EmailException('No BccConfig available. Set the config along with the mailMode.'); + } + } + $this->mailMode = $mailMode; + return $this; + } + + public function getSmtpConfig() { + return $this->smtpConfig; + } + + public function setSmtpConfig($config) { + if (($config == NULL) || is_a($config, 'TgEmail\\Config\\SmtpConfig')) { + $this->smtpConfig = $config; + return $this; + } + throw new EmailException('Not a SmtpConfig object.'); + } + + public function getRerouteConfig() { + return $this->rerouteConfig; + } + + public function setRerouteConfig($config) { + if (($config == NULL) || is_a($config, 'TgEmail\\Config\\RerouteConfig')) { + $this->rerouteConfig = $config; + return $this; + } + throw new EmailException('Not a RerouteConfig object.'); + } + + public function getBccConfig() { + return $this->bccConfig; + } + + public function setBccConfig($config) { + if (($config == NULL) || is_a($config, 'TgEmail\\Config\\BccConfig')) { + $this->bccConfig = $config; + return $this; + } + throw new EmailException('Not a BccConfig object.'); + } + + public function getDefaultSender() { + return $this->defaultSender; + } + + public function setDefaultSender($email, $name = NULL) { + $this->defaultSender = EmailAddress::from($email, $name); + return $this; + } + + public function getDebugAddress() { + return $this->debugAddress; + } + + public function addDebugAddress($address, $name = NULL) { + if (is_array($address)) { + foreach ($address AS $a) { + $this->addDebugAddress($a); + } + } else if (is_string($address)) { + $this->debugAddress[] = EmailAddress::from($address, $name); + } else if (is_object($address)) { + $this->debugAddress[] = EmailAddress::from($address); + } else { + throw new EmailException('Cannot add debugging recipient(s)'); + } + return $this; + } + + public function getSubjectPrefix() { + if ($this->subjectPrefix == NULL) return ''; + return $this->subjectPrefix; + } + + public function setSubjectPrefix($s) { + $this->subjectPrefix = $s; + } + + public static function from($config) { + if (is_array($config)) { + $config = json_decode(json_encode($config)); + } else if (is_string($config)) { + $config = json_decode($config); + } + if (is_object($config)) { + $rc = new EmailConfig(); + if (isset($config->timezone)) { + $rc->setTimezone($config->timezone); + } + if (isset($config->smtpConfig)) { + $rc->setSmtpConfig(SmtpConfig::from($config->smtpConfig)); + } + if (isset($config->rerouteConfig)) { + $rc->setRerouteConfig(RerouteConfig::from($config->rerouteConfig)); + } + if (isset($config->bccConfig)) { + $rc->setBccConfig(BccConfig::from($config->bccConfig)); + } + if (isset($config->mailMode)) { + $rc->setMailMode($config->mailMode); + } + if (isset($config->debugAddress)) { + $rc->addDebugAddress($config->debugAddress); + } + if (isset($config->defaultSender)) { + $rc->setDefaultSender($config->defaultSender); + } + if (isset($config->subjectPrefix)) { + $rc->setSubjectPrefix($config->subjectPrefix); + } + return $rc; + } + throw new EmailException('Cannot create EmailConfig object from given config'); + } + +} + diff --git a/src/TgEmail/EmailException.php b/src/TgEmail/EmailException.php new file mode 100644 index 0000000..6d4062e --- /dev/null +++ b/src/TgEmail/EmailException.php @@ -0,0 +1,22 @@ +config = $config; + $this->mailDAO = $mailDAO; + $this->mailer = NULL; + } + + public function createTestMail() { + $rc = new Email(); + $rc->setSender($this->config->getDefaultSender()); + $rc->setBody(Email::TEXT, 'This is a successfull e-mail test (TXT)'); + $rc->setBody(Email::HTML, '

Success

This is a successfull e-mail test (HTML)

'); + $rc->addTo($this->config->getDebugAddress()); + $rc->setSubject($this->config->getSubjectPrefix() . 'Test-Mail'); + return $rc; + } + + /** + * Sends a test-mail to private account + */ + public function sendTestMail() { + $email = $this->createTestMail(); + return $this->_send($email); + } + + /** + * Set a new mail mode. + * @param string $mailMode - the new mail mode + * @param object $config - the configuration of this mail mode (optional when config already available or not required) + */ + public function setMailMode($mailMode, $config = NULL) { + $this->config->setMailMode($mailMode, $config); + } + + /** + * TODO: smth like queue($email, $recipients) ? + * Sends multiple emails. + * + * @param + * array of + * mixed recipients - array of recipients or single recipient to send to + * string templateName - mail template name to be used, located in /site/email//.[html|txt].php + * string subject - subject + * mixed params - parameters to be given to email template + * string domain - the domain this mail belongs to + * @return array of + * boolean success - overall success + * array errors - individual boolean return codes for each mail + * + public function queueMails($mailInfos) { + $rc = array( + 'success' => true, + 'errors' => array(), + ); + foreach ($mailInfos as $mail) { + $c = $this->queueMail($mail['recipients'], $mail['templateName'], $mail['subject'], $mail['params']); + $rc['error'][] = $c; + if (! $c) $rc['success'] = false; + } + return $rc; + } + */ + + protected function getMailer() { + if ($this->mailer == null) { + $this->mailer = new PHPMailer(); + $this->mailer->IsSMTP(); // telling the class to use SMTP + $this->mailer->SMTPDebug = $this->config->getSmtpConfig()->getDebugLevel(); + $this->mailer->SMTPAuth = $this->config->getSmtpConfig()->isAuth(); + $this->mailer->SMTPSecure = $this->config->getSmtpConfig()->getSecureOption(); + $this->mailer->Port = $this->config->getSmtpConfig()->getPort(); + $this->mailer->Host = $this->config->getSmtpConfig()->getHost(); + $this->mailer->Username = $this->config->getSmtpConfig()->getUsername(); + $this->mailer->Password = $this->config->getSmtpConfig()->getPassword(); + $this->mailer->CharSet = $this->config->getSmtpConfig()->getCharset(); + $this->mailer->Encoding = 'base64'; + } else { + $this->mailer->clearAllRecipients(); + $this->mailer->clearAttachments(); + $this->mailer->clearCustomHeaders(); + $this->mailer->clearReplyTos(); + } + return $this->mailer; + } + + /** + * Synchronously send emails from queue according to priority. + */ + public function processQueue($maxTime = 0) { + if ($maxTime <= 0) $maxTime = 60; + + if ($this->mailDAO != NULL) { + // Make sure the request object was created + Request::getRequest(); + + // Return statistics + $rc = new \stdClass(); + $rc->pending = 0; + $rc->skipped = 0; + $rc->processed = 0; + $rc->sent = 0; + $rc->failed = 0; + + // do housekeeping + $this->mailDAO->housekeeping(); + + // Retrieve pending emails + $emails = $this->mailDAO->getPendingEmails(); + $rc->pending = count($emails); + foreach ($emails as $email) { + // send + if ($this->sendByUid($email->uid, TRUE)) { + $rc->sent++; + } else { + $rc->failed++; + } + $rc->processed++; + if (Request::getRequest()->getElapsedTime() > $maxTime) break; + } + return $rc; + } + throw new EmailException('QueueProcessing not supported. No DAO available.'); + } + + /** + * Synchronously send email from queue with id. + */ + public function sendByUid($uid, $checkStatus = FALSE) { + if ($this->mailDAO != NULL) { + // Retrieve + $email = $this->mailDAO->get($uid); + + if ($email != NULL) { + // Mark as being processed + $email->status = Email::PROCESSING; + $this->mailDAO->save($email); + + // send + $rc = $this->_send($email); + + // Save + $email->status = Email::SENT; + if (!$rc) { + $email->failed_attempts ++; + if ($email->failed_attempts >= 3) { + $email->status = Email::FAILED; + foreach ($email->getAttachments() AS $a) { + if ($a->deleteAfterSent && $a->deleteAfterFailed) { + unlink($a->path); + } + } + } else { + $email->status = Email::PENDING; + } + } else { + $email->sent_time = new Date(time(), $this->config->getTimezone()); + } + $this->mailDAO->save($email); + return $rc; + } + return FALSE; + } + throw new EmailException('No DAO available. Cannot retrieve e-mail by ID.'); + } + + /** + * Creates a new Email object that reflects the MailMode settings. + */ + public function getReconfiguredEmail(Email $email) { + $rc = new Email(); + + if ($email->getSender() != NULL) { + $rc->setSender($email->getSender()); + } else { + $rc->setSender($this->config->getDefaultSender()); + } + $rc->setReplyTo($email->getReplyTo()); + $rc->addAttachments($email->getAttachments()); + $rc->setBody(Email::TEXT, $email->getBody(Email::TEXT)); + $rc->setBody(Email::HTML, $email->getBody(Email::HTML)); + + if ($this->config->getMailMode() == EmailQueue::REROUTE) { + $rc->setSubject($this->config->getRerouteConfig()->getSubjectPrefix().$this->config->getSubjectPrefix().$email->getSubject().' - '.$email->stringify($email->getTo())); + $rc->addTo($this->config->getRerouteConfig()->getRecipients()); + } else { + $rc->setSubject($this->config->getSubjectPrefix().$email->getSubject()); + $rc->addTo($email->getTo()); + $rc->addCc($email->getCc()); + $rc->addBcc($email->getBcc()); + if ($this->config->getMailMode() == EmailQueue::BCC) { + $rc->addBcc($this->config->getBccConfig()->getRecipients()); + } + } + return $rc; + } + + public function send(Email $email) { + // Modify mail according to sending mode + $email = $this->getReconfiguredEmail($email); + return $this->_send($email); + } + + /** + * Synchronously send email object. + */ + protected function _send(Email $email) { + // Start + $phpMailer = $this->getMailer(); + + // Sender + $phpMailer->setFrom($email->getSender()->email, $email->getSender()->name); + + // Reply-To + if ($email->getReplyTo() != NULL) { + $phpMailer->addReplyTo($email->getReplyTo()->email, $email->getReplyTo()->name); + } + + // Recipients + foreach ($email->getTo() as $recipient) { + $phpMailer->addAddress($recipient->email, $recipient->name); + } + foreach ($email->getCc() as $recipient) { + $phpMailer->addCC($recipient->email, $recipient->name); + } + foreach ($email->getBcc() as $recipient) { + $phpMailer->addBCC($recipient->email, $recipient->name); + } + + // Subject + $phpMailer->Subject = '=?utf-8?B?' . base64_encode($email->getSubject()) . '?='; + + // Body + if ($email->getBody(Email::HTML) != NULL) { + $phpMailer->isHTML(true); + $phpMailer->Body = $email->getBody(Email::HTML); + if ($email->getBody(Email::TEXT) != NULL) { + $phpMailer->AltBody = $email->getBody(Email::TEXT); + } + } else { + $phpMailer->Body = $email->getBody(Email::TEXT); + } + + // Attachments + foreach ($email->getAttachments() as $a) { + if ($a->type == Attachment::ATTACHED) { + $phpMailer->AddAttachment($a->path, $a->name, 'base64', $a->mimeType); + } else if ($a->type == 'embedded') { + $phpMailer->AddEmbeddedImage($a->path, $a->cid, $a->name); + } + } + + $rc = TRUE; + if ($this->config->getMailMode() != EmailQueue::BLOCK) { + $rc = $phpMailer->send(); + Log::debug('Mail sent: '.$email->getLogString()); + if (!$rc) { + Log::error("Mailer Error: " . $phpMailer->ErrorInfo); + } else { + foreach ($email->getAttachments() as $a) { + if ($a->deleteAfterSent) { + unlink($a->path); + } + } + } + } + return $rc; + } + + public function queue(Email $email) { + // Modify mail according to sending mode + $email = $this->getReconfiguredEmail($email); + return $this->_queue($email); + } + + /** + * Queues an email. + * + * @param Email $email + * - \WebApp\Email object + * @return true when e-mail was queued + */ + protected function _queue($email) { + if ($this->mailDAO != NULL) { + if ($this->config->getMailMode() != EmailQueue::BLOCK) { + $email->queued_time = new Date(time(), $this->config->getTimezone()); + $email->status = Email::PENDING; + $email->failed_attempts = 0; + $email->sent_time = NULL; + $rc = $this->mailDAO->create($email); + return is_int($rc); + } + return TRUE; + } + throw new EmailException('Queueing is not supported. No DAO available.'); + } + +} + diff --git a/src/TgEmail/EmailsDAO.php b/src/TgEmail/EmailsDAO.php new file mode 100644 index 0000000..f4adb9d --- /dev/null +++ b/src/TgEmail/EmailsDAO.php @@ -0,0 +1,58 @@ +checkTable(); + } + + public function checkTable() { + $res = $this->database->query('SELECT * FROM '.$this->tableName); + if ($res === FALSE) { + // Create it (try) + $sql = + 'CREATE TABLE `'.$this->tableName.'` ( '. + '`'.$this->idColumn.'` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT \'ID of queue element\', '. + '`sender` VARCHAR(200) NOT NULL COMMENT \'sender address\', '. + '`reply_to` VARCHAR(200) NULL COMMENT \'Reply-To address\', '. + '`recipients` TEXT COLLATE utf8mb4_bin NOT NULL COMMENT \'email recipients\', '. + '`subject` VARCHAR(200) NOT NULL COMMENT \'email subject\', '. + '`body` TEXT COLLATE utf8mb4_bin NOT NULL COMMENT \'email bodies\', '. + '`attachments` TEXT COLLATE utf8mb4_bin NOT NULL COMMENT \'attachment data\', '. + '`queued_time` DATETIME NOT NULL COMMENT \'Time the email was queued\', '. + '`status` VARCHAR(20) NOT NULL COMMENT \'email subject\', '. + '`sent_time` DATETIME NULL COMMENT \'Time the email was sent successfully\', '. + '`failed_attempts` INT(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT \'Number of failed sending attempts\', '. + 'PRIMARY KEY (`'.$this->idColumn.'`) '. + ') ENGINE = InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT = \'Email Queue\''; + + $res = $this->database->query($sql); + if ($res === FALSE) { + throw new EmailException('Cannot create table '.$this->tableName.': '.$this->database->error()); + } + } + + } + + public function housekeeping($maxSentDays = 90, $maxFailedDays = 180) { + $this->database->delete($this->tableName, 'status=\'sent\' AND TIMESTAMPDIFF(DAY, sent_time, NOW()) >= '.$maxSentDays); + $this->database->delete($this->tableName, 'status=\'failed\' AND TIMESTAMPDIFF(DAY, sent_time, NOW()) >= '.$maxFailedDays); + } + + public function getPendingEmails() { + return $this->find(array('status' => Email::PENDING), array('queued_time')); + } +} + diff --git a/tests/TgEmail/Config/BccConfigTest.php b/tests/TgEmail/Config/BccConfigTest.php new file mode 100644 index 0000000..a2d009d --- /dev/null +++ b/tests/TgEmail/Config/BccConfigTest.php @@ -0,0 +1,90 @@ +addRecipients('John Doe getRecipients(); + $this->assertEquals(1, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + } + + public function testAddRecipientsWithObject(): void { + $config = new BccConfig(); + $config->addRecipients(EmailAddress::from('John Doe getRecipients(); + $this->assertEquals(1, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + } + + public function testAddRecipientsWithArray(): void { + $config = new BccConfig(); + $config->addRecipients(array( + EmailAddress::from('John Doe getRecipients(); + $this->assertEquals(2, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + $this->assertEquals('Jane Doe ', $recipients[1]->__toString()); + } + + public function testFromWithArray(): void { + $origConfig = array( + 'recipients' => array( + 'John Doe 'Jane Doe', + 'email' => 'jane.doe@example.com', + ), + ), + ); + + $config = BccConfig::from($origConfig); + $recipients = $config->getRecipients(); + $this->assertEquals(2, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + $this->assertEquals('Jane Doe ', $recipients[1]->__toString()); + } + + public function testFromWithString(): void { + $origConfig = self::getJsonTestString(); + + $config = BccConfig::from($origConfig); + $recipients = $config->getRecipients(); + $this->assertEquals(2, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + $this->assertEquals('Jane Doe ', $recipients[1]->__toString()); + } + + public function testFromWithObject(): void { + $origConfig = json_decode(self::getJsonTestString()); + + $config = BccConfig::from($origConfig); + $recipients = $config->getRecipients(); + $this->assertEquals(2, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + $this->assertEquals('Jane Doe ', $recipients[1]->__toString()); + } + + public static function getJsonTestString() { + return '{"recipients":["John Doe addRecipients('John Doe getRecipients(); + $this->assertEquals(1, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + } + + public function testAddRecipientsWithObject(): void { + $config = new RerouteConfig(); + $config->addRecipients(EmailAddress::from('John Doe getRecipients(); + $this->assertEquals(1, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + } + + public function testAddRecipientsWithArray(): void { + $config = new RerouteConfig(); + $config->addRecipients(array( + EmailAddress::from('John Doe getRecipients(); + $this->assertEquals(2, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + $this->assertEquals('Jane Doe ', $recipients[1]->__toString()); + } + + public function testSetSubjectPrefix(): void { + $config = new RerouteConfig(); + $config->setSubjectPrefix('A specific prefix'); + $this->assertEquals('A specific prefix', $config->getSubjectPrefix()); + } + + public function testFromWithArray(): void { + $origConfig = array( + 'recipients' => array( + 'John Doe 'Jane Doe', + 'email' => 'jane.doe@example.com', + ), + ), + 'subjectPrefix' => 'A specific prefix', + ); + + $config = RerouteConfig::from($origConfig); + $recipients = $config->getRecipients(); + $this->assertEquals(2, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + $this->assertEquals('Jane Doe ', $recipients[1]->__toString()); + $this->assertEquals('A specific prefix', $config->getSubjectPrefix()); + } + + public function testFromWithString(): void { + $origConfig = self::getJsonTestString(); + + $config = RerouteConfig::from($origConfig); + $recipients = $config->getRecipients(); + $this->assertEquals(2, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + $this->assertEquals('Jane Doe ', $recipients[1]->__toString()); + $this->assertEquals('A specific prefix', $config->getSubjectPrefix()); + } + + public function testFromWithObject(): void { + $origConfig = json_decode(self::getJsonTestString()); + + $config = RerouteConfig::from($origConfig); + $recipients = $config->getRecipients(); + $this->assertEquals(2, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + $this->assertEquals('Jane Doe ', $recipients[1]->__toString()); + $this->assertEquals('A specific prefix', $config->getSubjectPrefix()); + } + + public static function getJsonTestString() { + return '{"recipients":["John Doe setHost('www.example.com'); + $this->assertEquals('www.example.com', $config->getHost()); + } + + public function testSetPort(): void { + $config = new SmtpConfig(); + $config->setPort(587); + $this->assertEquals(587, $config->getPort()); + } + + public function testSetDebugLevel(): void { + $config = new SmtpConfig(); + $config->setDebuglevel(SMTP::DEBUG_SERVER); + $this->assertEquals(SMTP::DEBUG_SERVER, $config->getDebuglevel()); + } + + + public function testSetAuth(): void { + $config = new SmtpConfig(); + $config->setAuth(TRUE); + $this->assertTrue($config->isAuth()); + } + + + public function testSetCredentials(): void { + $config = new SmtpConfig(); + $config->setCredentials('username', 'password'); + $this->assertEquals('username', $config->getUsername()); + $this->assertEquals('password', $config->getPassword()); + } + + + public function testSetSecureOption(): void { + $config = new SmtpConfig(); + $config->setSecureOption(PHPMailer::ENCRYPTION_STARTTLS); + $this->assertEquals(PHPMailer::ENCRYPTION_STARTTLS, $config->getSecureOption()); + } + + + public function testSetCharset(): void { + $config = new SmtpConfig(); + $config->setCharset('utf8'); + $this->assertEquals('utf8', $config->getCharset()); + } + + public function testFromWithArray(): void { + $origConfig = array( + 'host' => 'www.example.com', + 'port' => 587, + 'debugLevel' => SMTP::DEBUG_SERVER, + 'auth' => TRUE, + 'credentials' => array( + 'user' => 'username', + 'pass' => 'password', + ), + 'secureOption' => PHPMailer::ENCRYPTION_STARTTLS, + 'charset' => 'utf8', + ); + + $config = SmtpConfig::from($origConfig); + $this->assertEquals('www.example.com', $config->getHost()); + $this->assertEquals(587, $config->getPort()); + $this->assertEquals(SMTP::DEBUG_SERVER, $config->getDebuglevel()); + $this->assertTrue($config->isAuth()); + $this->assertEquals('username', $config->getUsername()); + $this->assertEquals('password', $config->getPassword()); + $this->assertEquals(PHPMailer::ENCRYPTION_STARTTLS, $config->getSecureOption()); + $this->assertEquals('utf8', $config->getCharset()); + } + + public function testFromWithString(): void { + $origConfig = self::getJsonTestString(); + + $config = SmtpConfig::from($origConfig); + $this->assertEquals('www.example.com', $config->getHost()); + $this->assertEquals(587, $config->getPort()); + $this->assertEquals(SMTP::DEBUG_SERVER, $config->getDebuglevel()); + $this->assertTrue($config->isAuth()); + $this->assertEquals('username', $config->getUsername()); + $this->assertEquals('password', $config->getPassword()); + $this->assertEquals(PHPMailer::ENCRYPTION_STARTTLS, $config->getSecureOption()); + $this->assertEquals('utf8', $config->getCharset()); + } + + public function testFromWithObject(): void { + $origConfig = json_decode(self::getJsonTestString()); + + $config = SmtpConfig::from($origConfig); + $this->assertEquals('www.example.com', $config->getHost()); + $this->assertEquals(587, $config->getPort()); + $this->assertEquals(SMTP::DEBUG_SERVER, $config->getDebuglevel()); + $this->assertTrue($config->isAuth()); + $this->assertEquals('username', $config->getUsername()); + $this->assertEquals('password', $config->getPassword()); + $this->assertEquals(PHPMailer::ENCRYPTION_STARTTLS, $config->getSecureOption()); + $this->assertEquals('utf8', $config->getCharset()); + } + + public static function getJsonTestString() { + return '{"host":"www.example.com","port":587,"debugLevel":2,"auth":true,"credentials":{"user":"username","pass":"password"},"secureOption":"tls","charset":"utf8"}'; + } +} + diff --git a/tests/TgEmail/EmailAddressTest.php b/tests/TgEmail/EmailAddressTest.php new file mode 100644 index 0000000..5be8b1a --- /dev/null +++ b/tests/TgEmail/EmailAddressTest.php @@ -0,0 +1,59 @@ +assertEquals('', $addr->__toString()); + } + + public function testToStringWithEmailName(): void { + $addr = new EmailAddress('john.doe@example.com', 'John Doe'); + $this->assertEquals('John Doe ', $addr->__toString()); + } + + public function testFromWithEmail1(): void { + $addr = EmailAddress::from('john.doe@example.com'); + $this->assertEquals('', $addr->__toString()); + } + + public function testFromWithEmail2(): void { + $addr = EmailAddress::from(''); + $this->assertEquals('', $addr->__toString()); + } + + public function testFromWithString(): void { + $addr = EmailAddress::from('John Doe '); + $this->assertEquals('John Doe ', $addr->__toString()); + } + + public function testFromWithEmailName(): void { + $addr = EmailAddress::from('john.doe@example.com', 'John Doe'); + $this->assertEquals('John Doe ', $addr->__toString()); + } + + public function testFromWithObject(): void { + $obj = new \stdClass; + $obj->name = 'John Doe'; + $obj->email = 'john.doe@example.com'; + $addr = EmailAddress::from($obj); + $this->assertEquals('John Doe ', $addr->__toString()); + } + + public function testFromWithAddress(): void { + $obj = new EmailAddress('john.doe@example.com', 'John Doe'); + $addr = EmailAddress::from($obj); + $this->assertEquals('John Doe ', $addr->__toString()); + } +} + diff --git a/tests/TgEmail/EmailConfigTest.php b/tests/TgEmail/EmailConfigTest.php new file mode 100644 index 0000000..1cfab09 --- /dev/null +++ b/tests/TgEmail/EmailConfigTest.php @@ -0,0 +1,158 @@ +setTimezone('Europe/Berlin'); + $this->assertEquals('Europe/Berlin', $config->getTimezone()); + } + + public function testSetMailMode(): void { + $config = new EmailConfig(); + $config->setMailMode(EmailQueue::BLOCK); + $this->assertEquals(EmailQueue::BLOCK, $config->getMailMode()); + } + + public function testSetSmtpConfig(): void { + $config = new EmailConfig(); + $smtpConfig = SmtpConfig::from(SmtpConfigTest::getJsonTestString()); + $config->setSmtpConfig($smtpConfig); + $this->assertEquals($smtpConfig, $config->getSmtpConfig()); + } + + + public function testSetRerouteConfig(): void { + $config = new EmailConfig(); + $rerouteConfig = RerouteConfig::from(RerouteConfigTest::getJsonTestString()); + $config->setRerouteConfig($rerouteConfig); + $this->assertEquals($rerouteConfig, $config->getRerouteConfig()); + } + + public function testSetBccConfig(): void { + $config = new EmailConfig(); + $bccConfig = BccConfig::from(BccConfigTest::getJsonTestString()); + $config->setBccConfig($bccConfig); + $this->assertEquals($bccConfig, $config->getBccConfig()); + } + + public function testAddDebugAddressWithString(): void { + $config = new EmailConfig(); + $config->addDebugAddress('John Doe getDebugAddress(); + $this->assertEquals(1, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + } + + public function testAddDebugAddressWithObject(): void { + $config = new EmailConfig(); + $config->addDebugAddress(EmailAddress::from('John Doe getDebugAddress(); + $this->assertEquals(1, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + } + + public function testAddDebugAddressWithArray(): void { + $config = new EmailConfig(); + $config->addDebugAddress(array( + EmailAddress::from('John Doe getDebugAddress(); + $this->assertEquals(2, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + $this->assertEquals('Jane Doe ', $recipients[1]->__toString()); + } + + public function testSetDefaultSender(): void { + $config = new EmailConfig(); + $config->setDefaultSender(EmailAddress::from('John Doe ')); + $this->assertEquals('John Doe ', $config->getDefaultSender()->__toString()); + } + + public function testSetSubjectPrefix(): void { + $config = new EmailConfig(); + $config->setSubjectPrefix('A subject prefix'); + $this->assertEquals('A subject prefix', $config->getSubjectPrefix()); + } + + + public function testFromWithArray(): void { + $origConfig = array( + 'timezone' => 'Europe/Berlin', + 'mailMode' => EmailQueue::BLOCK, + 'smtpConfig' => json_decode(SmtpConfigTest::getJsonTestString(), TRUE), + 'rerouteConfig' => json_decode(RerouteConfigTest::getJsonTestString(), TRUE), + 'bccConfig' => json_decode(BccConfigTest::getJsonTestString(), TRUE), + 'debugAddress' => 'Jane Doe 'John Doe 'A subject prefix', + ); + + $config = EmailConfig::from($origConfig); + $this->assertEquals('Europe/Berlin', $config->getTimezone()); + $this->assertEquals(EmailQueue::BLOCK, $config->getMailMode()); + $this->assertInstanceOf(SmtpConfig::class, $config->getSmtpConfig()); + $this->assertInstanceOf(RerouteConfig::class, $config->getRerouteConfig()); + $this->assertInstanceOf(BccConfig::class, $config->getBccConfig()); + $this->assertEquals('Jane Doe ', $config->getDebugAddress()[0]->__toString()); + $this->assertEquals('John Doe ', $config->getDefaultSender()->__toString()); + $this->assertEquals('A subject prefix', $config->getSubjectPrefix()); + } + + public function testFromWithString(): void { + $origConfig = self::getJsonTestString(); + + $config = EmailConfig::from($origConfig); + $this->assertEquals('Europe/Berlin', $config->getTimezone()); + $this->assertEquals(EmailQueue::BLOCK, $config->getMailMode()); + $this->assertInstanceOf(SmtpConfig::class, $config->getSmtpConfig()); + $this->assertInstanceOf(RerouteConfig::class, $config->getRerouteConfig()); + $this->assertInstanceOf(BccConfig::class, $config->getBccConfig()); + $this->assertEquals('Jane Doe ', $config->getDebugAddress()[0]->__toString()); + $this->assertEquals('John Doe ', $config->getDefaultSender()->__toString()); + $this->assertEquals('A subject prefix', $config->getSubjectPrefix()); + } + + public function testFromWithObject(): void { + $origConfig = json_decode(self::getJsonTestString()); + + $config = EmailConfig::from($origConfig); + $this->assertEquals('Europe/Berlin', $config->getTimezone()); + $this->assertEquals(EmailQueue::BLOCK, $config->getMailMode()); + $this->assertInstanceOf(SmtpConfig::class, $config->getSmtpConfig()); + $this->assertInstanceOf(RerouteConfig::class, $config->getRerouteConfig()); + $this->assertInstanceOf(BccConfig::class, $config->getBccConfig()); + $this->assertEquals('Jane Doe ', $config->getDebugAddress()[0]->__toString()); + $this->assertEquals('John Doe ', $config->getDefaultSender()->__toString()); + $this->assertEquals('A subject prefix', $config->getSubjectPrefix()); + } + + public static function getJsonTestString() { + return '{"timezone":"Europe\/Berlin","mailMode":"block","smtpConfig":{"host":"www.example.com","port":587,"debugLevel":2,"auth":true,"credentials":{"user":"username","pass":"password"},"secureOption":"tls","charset":"utf8"},"rerouteConfig":{"recipients":["John Doe This class requires enviroment variable EMAIL_DATABASE and EMAIL_TEST_SMTP + * to contain the configuration for the database access and SMTP parameters + * to successfully test the sending and queuing.

+ * @author ralph + * + */ +class EmailQueueTest extends TestCase { + + private static $database = NULL; + private static $dao = NULL; + private static $queue = NULL; + private static $queueConfig = NULL; + + public function testSendWithBlocked(): void { + if (getenv('EMAIL_TEST_SMTP') != NULL) { + $config = json_decode(getenv('EMAIL_TEST_SMTP')); + $queue = self::getEmailQueue(EmailQueue::BLOCK); + $email = new Email(); + $email->setSubject('[EmailQueueTest] testSendWithBlocked'); + $email->setBody(Email::HTML, '

EmailQueueTest::testSendWithBlocked

This email shall not have been delivered! Test failed.

'); + $email->setBody(Email::TEXT, "EmailQueueTest::testSendWithBlocked\n=================\n\nThis email shall not have been delivered! Test failed.\n"); + $email->addTo(EmailAddress::from($config->targetAddress)); + if (isset($config->replyToAddress)) $email->setReplyTo(EmailAddress::from($config->replyToAddress)); + + $this->assertTrue($queue->send($email)); + } else { + // Just to not create a test warning + $this->assertTrue(TRUE); + } + } + + public function testSendWithReroute(): void { + if (getenv('EMAIL_TEST_SMTP') != NULL) { + $config = json_decode(getenv('EMAIL_TEST_SMTP')); + $queue = self::getEmailQueue(EmailQueue::REROUTE); + $email = new Email(); + $email->setSubject('testSendWithReroute'); + $email->setBody(Email::HTML, '

EmailQueueTest::testSendWithReroute

This email shall have arrived at your reroute mailbox: '.self::$queueConfig->getRerouteConfig()->getRecipients()[0]->email.'

'); + $email->setBody(Email::TEXT, "EmailQueueTest::testSendWithReroute\n=================\n\nThis email shall have arrived at your reroute mailbox: ".self::$queueConfig->getRerouteConfig()->getRecipients()[0]->email."\n"); + $email->addTo(EmailAddress::from($config->targetAddress)); + if (isset($config->replyToAddress)) $email->setReplyTo(EmailAddress::from($config->replyToAddress)); + + $this->assertTrue($queue->send($email)); + } else { + // Just to not create a test warning + $this->assertTrue(TRUE); + } + } + + public function testSendWithBcc(): void { + if (getenv('EMAIL_TEST_SMTP') != NULL) { + $config = json_decode(getenv('EMAIL_TEST_SMTP')); + $queue = self::getEmailQueue(EmailQueue::BCC); + $email = new Email(); + $email->setSubject('testSendWithBcc'); + $email->setBody(Email::HTML, '

EmailQueueTest::testSendWithBcc

This email shall have arrived at your BCC mailbox: '.self::$queueConfig->getBccConfig()->getRecipients()[0]->email.'

'); + $email->setBody(Email::TEXT, "EmailQueueTest::testSendWithBcc\n=================\n\nThis email shall have arrived at your target mailbox: ".self::$queueConfig->getBccConfig()->getRecipients()[0]->email."\n"); + $email->addTo(EmailAddress::from($config->targetAddress)); + if (isset($config->replyToAddress)) $email->setReplyTo(EmailAddress::from($config->replyToAddress)); + + $this->assertTrue($queue->send($email)); + } else { + // Just to not create a test warning + $this->assertTrue(TRUE); + } + } + + public function testSendWithDefault(): void { + if (getenv('EMAIL_TEST_SMTP') != NULL) { + $config = json_decode(getenv('EMAIL_TEST_SMTP')); + $queue = self::getEmailQueue(EmailQueue::DEFAULT); + $email = new Email(); + $email->setSubject('testSendWithDefault'); + $email->setBody(Email::HTML, '

EmailQueueTest::testSendWithReroute

This email shall have arrived at your normal mailbox: '.$config->targetAddress.'

'); + $email->setBody(Email::TEXT, "EmailQueueTest::testSendWithReroute\n=================\n\nThis email shall have arrived at your target mailbox: ".$config->targetAddress."\n"); + $email->addTo(EmailAddress::from($config->targetAddress)); + if (isset($config->replyToAddress)) $email->setReplyTo(EmailAddress::from($config->replyToAddress)); + + $this->assertTrue($queue->send($email)); + } else { + // Just to not create a test warning + $this->assertTrue(TRUE); + } + } + + public function testQueueWithBlocked(): void { + if ((getenv('EMAIL_TEST_SMTP') != NULL) && (getenv('EMAIL_DATABASE') != NULL)) { + $config = json_decode(getenv('EMAIL_TEST_SMTP')); + $queue = self::getEmailQueue(EmailQueue::BLOCK); + $email = new Email(); + $email->setSubject('[EmailQueueTest] testQueueWithBlocked'); + $email->setBody(Email::HTML, '

EmailQueueTest::testQueueWithBlocked

This email shall not have been delivered! Test failed.

'); + $email->setBody(Email::TEXT, "EmailQueueTest::testQueueWithBlocked\n=================\n\nThis email shall not have been delivered! Test failed.\n"); + $email->addTo(EmailAddress::from($config->targetAddress)); + if (isset($config->replyToAddress)) $email->setReplyTo(EmailAddress::from($config->replyToAddress)); + + $this->assertTrue($rc = $queue->queue($email)); + + // Now process the queue + $rc = $queue->processQueue(); + $this->assertTrue($rc->sent >= 0); + } else { + // Just to not create a test warning + $this->assertTrue(TRUE); + } + } + + public function testQueueWithReroute(): void { + if ((getenv('EMAIL_TEST_SMTP') != NULL) && (getenv('EMAIL_DATABASE') != NULL)) { + $config = json_decode(getenv('EMAIL_TEST_SMTP')); + $queue = self::getEmailQueue(EmailQueue::REROUTE); + $email = new Email(); + $email->setSubject('testQueueWithReroute'); + $email->setBody(Email::HTML, '

EmailQueueTest::testQueueWithReroute

This email shall have arrived at your reroute mailbox: '.self::$queueConfig->getRerouteConfig()->getRecipients()[0]->email.'

'); + $email->setBody(Email::TEXT, "EmailQueueTest::testQueueWithReroute\n=================\n\nThis email shall have arrived at your reroute mailbox: ".self::$queueConfig->getRerouteConfig()->getRecipients()[0]->email."\n"); + $email->addTo(EmailAddress::from($config->targetAddress)); + if (isset($config->replyToAddress)) $email->setReplyTo(EmailAddress::from($config->replyToAddress)); + + $this->assertTrue($rc = $queue->queue($email)); + + // Now process the queue + $rc = $queue->processQueue(); + $this->assertTrue($rc->sent >= 1); + } else { + // Just to not create a test warning + $this->assertTrue(TRUE); + } + } + + public function testQueueWithBcc(): void { + if ((getenv('EMAIL_TEST_SMTP') != NULL) && (getenv('EMAIL_DATABASE') != NULL)) { + $config = json_decode(getenv('EMAIL_TEST_SMTP')); + $queue = self::getEmailQueue(EmailQueue::BCC); + $email = new Email(); + $email->setSubject('testQueueWithBcc'); + $email->setBody(Email::HTML, '

EmailQueueTest::testQueueWithBcc

This email shall have arrived at your BCC mailbox: '.self::$queueConfig->getBccConfig()->getRecipients()[0]->email.'

'); + $email->setBody(Email::TEXT, "EmailQueueTest::testQueueWithBcc\n=================\n\nThis email shall have arrived at your target mailbox: ".self::$queueConfig->getBccConfig()->getRecipients()[0]->email."\n"); + $email->addTo(EmailAddress::from($config->targetAddress)); + if (isset($config->replyToAddress)) $email->setReplyTo(EmailAddress::from($config->replyToAddress)); + + $this->assertTrue($rc = $queue->queue($email)); + + // Now process the queue + $rc = $queue->processQueue(); + $this->assertTrue($rc->sent >= 1); + } else { + // Just to not create a test warning + $this->assertTrue(TRUE); + } + } + + public function testQueueWithDefault(): void { + if ((getenv('EMAIL_TEST_SMTP') != NULL) && (getenv('EMAIL_DATABASE') != NULL)) { + $config = json_decode(getenv('EMAIL_TEST_SMTP')); + $queue = self::getEmailQueue(EmailQueue::DEFAULT); + $email = new Email(); + $email->setSubject('testQueueWithDefault'); + $email->setBody(Email::HTML, '

EmailQueueTest::testQueueWithReroute

This email shall have arrived at your normal mailbox: '.$config->targetAddress.'

'); + $email->setBody(Email::TEXT, "EmailQueueTest::testQueueWithReroute\n=================\n\nThis email shall have arrived at your target mailbox: ".$config->targetAddress."\n"); + $email->addTo(EmailAddress::from($config->targetAddress)); + if (isset($config->replyToAddress)) $email->setReplyTo(EmailAddress::from($config->replyToAddress)); + + $this->assertTrue($rc = $queue->queue($email)); + + // Now process the queue + $rc = $queue->processQueue(); + $this->assertTrue($rc->sent >= 1); + } else { + // Just to not create a test warning + $this->assertTrue(TRUE); + } + } + + public static function getMailDAO() { + Log::setDefaultLogLevel(Log::ERROR); + if ((self::$database == NULL) && (getenv('EMAIL_DATABASE') != NULL)) { + $config = json_decode(getenv('EMAIL_DATABASE'), TRUE); + self::$database = new Database($config); + self::$dao = new EmailsDAO(self::$database); + self::$dao->deleteBy(); + } + return self::$dao; + } + + public static function getEmailQueue($mailMode) { + if ((self::$queue == NULL) && getenv('EMAIL_TEST_SMTP') != NULL) { + self::$queueConfig = EmailConfig::from(getenv('EMAIL_TEST_SMTP')); + self::$queue = new EmailQueue(self::$queueConfig, self::getMailDAO()); + } + if (self::$queueConfig != NULL) { + self::$queueConfig->setMailMode($mailMode); + } + return self::$queue; + } + +} + diff --git a/tests/TgEmail/EmailTest.php b/tests/TgEmail/EmailTest.php new file mode 100644 index 0000000..18aabda --- /dev/null +++ b/tests/TgEmail/EmailTest.php @@ -0,0 +1,139 @@ +setSender(EmailAddress::from('John Doe ')); + $this->assertEquals('John Doe ', $email->getSender()->__toString()); + } + + public function testSetReplyTo(): void { + $email = new Email(); + $email->setReplyTo(EmailAddress::from('John Doe ')); + $this->assertEquals('John Doe ', $email->getReplyTo()->__toString()); + } + + public function testAddToWithString(): void { + $email = new Email(); + $email->addTo('John Doe getTo(); + $this->assertEquals(1, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + } + + public function testAddToWithObject(): void { + $email = new Email(); + $email->addTo(EmailAddress::from('John Doe getTo(); + $this->assertEquals(1, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + } + + public function testAddToWithArray(): void { + $email = new Email(); + $email->addTo(array( + EmailAddress::from('John Doe getTo(); + $this->assertEquals(2, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + $this->assertEquals('Jane Doe ', $recipients[1]->__toString()); + } + + public function testAddCcWithString(): void { + $email = new Email(); + $email->addCc('John Doe getCc(); + $this->assertEquals(1, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + } + + public function testAddCcWithObject(): void { + $email = new Email(); + $email->addCc(EmailAddress::from('John Doe getCc(); + $this->assertEquals(1, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + } + + public function testAddCcWithArray(): void { + $email = new Email(); + $email->addCc(array( + EmailAddress::from('John Doe getCc(); + $this->assertEquals(2, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + $this->assertEquals('Jane Doe ', $recipients[1]->__toString()); + } + + public function testAddBccWithString(): void { + $email = new Email(); + $email->addBcc('John Doe getBcc(); + $this->assertEquals(1, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + } + + public function testAddBccWithObject(): void { + $email = new Email(); + $email->addBcc(EmailAddress::from('John Doe getBcc(); + $this->assertEquals(1, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + } + + public function testAddBccWithArray(): void { + $email = new Email(); + $email->addBcc(array( + EmailAddress::from('John Doe getBcc(); + $this->assertEquals(2, count($recipients)); + $this->assertEquals('John Doe ', $recipients[0]->__toString()); + $this->assertEquals('Jane Doe ', $recipients[1]->__toString()); + } + + public function testSetSubject(): void { + $email = new Email(); + $email->setSubject('A subject'); + $this->assertEquals('A subject', $email->getSubject()); + } + + public function testSetHtmlBody(): void { + $email = new Email(); + $email->setBody(Email::HTML, 'A HTML body text'); + $this->assertEquals('A HTML body text', $email->getBody(Email::HTML)); + } + + public function testSetTextBody(): void { + $email = new Email(); + $email->setBody(Email::TEXT, 'A plain body text'); + $this->assertEquals('A plain body text', $email->getBody(Email::TEXT)); + } + + +} +