diff --git a/config-templates/config.php b/config-templates/config.php index aecb8f0177e2c9491382f21a7bca5f202bf77c82..d260765594d7892d73ef1a503b5ccf3ea0d1c75a 100644 --- a/config-templates/config.php +++ b/config-templates/config.php @@ -75,6 +75,31 @@ $config = [ 'technicalcontact_name' => 'Administrator', 'technicalcontact_email' => 'na@example.org', + /* + * (Optional) The method by which email is delivered. Defaults to mail which utilizes the + * PHP mail() function. + * + * Valid options are: mail, sendmail and smtp. + */ + //'mail.transport.method' => 'smtp', + + /* + * Set the transport options for the transport method specified. The valid settings are relative to the + * selected transport method. + */ + // // smtp mail transport options + // 'mail.transport.options' => [ + // 'host' => 'mail.example.org', // required + // 'port' => 25, // optional + // 'username' => 'user@example.org', // optional: if set, enables smtp authentication + // 'password' => 'password', // optional: if set, enables smtp authentication + // 'security' => 'tls', // optional: defaults to no smtp security + // ], + // // sendmail mail transport options + // 'mail.transport.options' => [ + // 'path' => '/usr/sbin/sendmail' // optional: defaults to php.ini path + // ], + /* * The envelope from address for outgoing emails. * This should be in a domain that has your application's IP addresses in its SPF record diff --git a/lib/SimpleSAML/Utils/EMail.php b/lib/SimpleSAML/Utils/EMail.php index 44871505a30a8378d00d2f371e045709346c421c..1bfd67b86950d4fd1a96fbf62d799cb7047a4b0a 100644 --- a/lib/SimpleSAML/Utils/EMail.php +++ b/lib/SimpleSAML/Utils/EMail.php @@ -47,6 +47,8 @@ class EMail $this->mail->Subject = $subject; $this->mail->setFrom($from ?: static::getDefaultMailAddress()); $this->mail->addAddress($to ?: static::getDefaultMailAddress()); + + static::initFromConfig($this); } @@ -143,6 +145,103 @@ class EMail $this->mail->send(); } + /** + * Sets the method by which the email will be sent. Currently supports what + * PHPMailer supports: sendmail, mail and smtp. + * + * @param string $transportMethod the transport method + * @param array $transportOptions options for the transport method + * + * @return void + * + * @throws \InvalidArgumentException + */ + public function setTransportMethod($transportMethod, array $transportOptions = []) + { + assert(is_string($transportMethod)); + assert(is_array($transportOptions)); + + + switch (strtolower($transportMethod)) { + // smtp transport method + case 'smtp': + $this->mail->isSMTP(); + + // set the host (required) + if (isset($transportOptions['host'])) { + $this->mail->Host = $transportOptions['host']; + } + // throw an exception otherwise + else { + throw new \InvalidArgumentException("Missing Required Email Transport Parameter 'host'"); + } + + // set the port (optional, assume standard SMTP port 25 if not provided) + $this->mail->Port = (isset($transportOptions['port'])) ? (int)$transportOptions['port'] : 25; + + // smtp auth: enabled if username or password is set + if (isset($transportOptions['username']) || isset($transportOptions['password'])) { + $this->mail->SMTPAuth = true; + } + + // smtp auth: username + if (isset($transportOptions['username'])) { + $this->mail->Username = $transportOptions['username']; + } + + // smtp auth: password + if (isset($transportOptions['password'])) { + $this->mail->Password = $transportOptions['password']; + } + + // smtp security: encryption type + if (isset($transportOptions['secure'])) { + $this->mail->SMTPSecure = $transportOptions['secure']; + } + + // smtp security: enable or disable smtp auto tls + if (isset($transportOptions['autotls'])) { + $this->mail->SMTPAutoTLS = (bool)$transportOptions['autotls']; + } + break; + //mail transport method + case 'mail': + $this->mail->isMail(); + break; + // sendmail transport method + case 'sendmail': + $this->mail->isSendmail(); + + // override the default path of the sendmail executable + if (isset($transportOptions['path'])) { + $this->mail->Sendmail = $transportOptions['path']; + } + break; + default: + throw new \InvalidArgumentException("Invalid Mail Transport Method - Check 'mail.transport.method' Configuration Option"); + } + } + + /** + * Initializes the provided EMail object with the configuration provided from the SimpleSAMLphp configuration. + * + * @param EMail $EMail + * @return EMail + * @throws \Exception + */ + public static function initFromConfig(EMail $EMail) + { + assert($EMail instanceof EMail); + + $config = Configuration::getInstance(); + $EMail->setTransportMethod( + $config->getString('mail.transport.method', 'mail'), + $config->getArrayize('mail.transport.options', []) + ); + + return $EMail; + } + /** * Generate the body of the e-mail diff --git a/tests/lib/SimpleSAML/Utils/EMailTestCase.php b/tests/lib/SimpleSAML/Utils/EMailTestCase.php index 971d6a2788a6255d15fb8c691e0dc621090bf99a..6c01432ca6ebcdd402962216858ca645d7d25713 100644 --- a/tests/lib/SimpleSAML/Utils/EMailTestCase.php +++ b/tests/lib/SimpleSAML/Utils/EMailTestCase.php @@ -71,4 +71,34 @@ class EMailTestCase extends ClearStateTestCase { return [['mailtxt.twig'], ['mailhtml.twig']]; } + + public function testInvalidTransportConfiguration() + { + // preserve the original configuration + $originalTestConfiguration = Configuration::getInstance()->toArray(); + + // load the configuration with an invalid mail.transport.method + Configuration::loadFromArray(array_merge($originalTestConfiguration, [ + 'mail.transport.method' => 'foobar' + ]), '[ARRAY]', 'simplesaml'); + + + $this->expectException(\InvalidArgumentException::class); + new Email('Test', 'phpunit@simplesamlphp.org', 'phpunit@simplesamlphp.org'); + + // reset the configuration + Configuration::loadFromArray($originalTestConfiguration, '[ARRAY]', 'simplesaml'); + } + + public function testInvalidSMTPConfiguration() + { + // setup a new email + $email = new Email('Test', 'phpunit@simplesamlphp.org', 'phpunit@simplesamlphp.org'); + + // set the transport option to smtp but don't set any transport options (invalid state) + // NOTE: this is the same method that the constructor calls, so this should be logically equivalent + // to setting it via the configuration file. + $this->expectException(\InvalidArgumentException::class); + $email->setTransportMethod('smtp'); + } }