Add MailerSend email service integration and templates
Introduced MailerSend as an email provider with essential configuration options, including API key management and "reply-to" support. Enhanced email functionality by implementing a modular template system (header, footer, and content) for both text and HTML formats. Updated the existing email infrastructure to handle Stripe invoice notifications via MailerSend with conditional fallback planned for default SMTP services.
This commit is contained in:
@@ -2,9 +2,27 @@
|
||||
|
||||
namespace classes;
|
||||
require_once WD . '/modules/email/email_c.php';
|
||||
require_once WD . '/modules/email/helpers/email_template.php';
|
||||
require_once WD . '/modules/email/templates/email_template_header.php';
|
||||
require_once WD . '/modules/email/templates/email_template_footer.php';
|
||||
require_once WD . '/modules/email/templates/email_template_head.php';
|
||||
require_once WD . '/modules/email/templates/email_template_stripe_invoice.php';
|
||||
|
||||
use email\email_c;
|
||||
use email\templates\email_template_footer;
|
||||
use email\templates\email_template_head;
|
||||
use email\templates\email_template_header;
|
||||
use email\templates\email_template_stripe_invoice;
|
||||
use Exception;
|
||||
use interfaces\email_i;
|
||||
use JsonException;
|
||||
use MailerSend\Exceptions\MailerSendAssertException;
|
||||
use MailerSend\Exceptions\MailerSendException;
|
||||
use MailerSend\Helpers\Builder\EmailParams;
|
||||
use MailerSend\Helpers\Builder\Header;
|
||||
use MailerSend\Helpers\Builder\Recipient;
|
||||
use MailerSend\MailerSend;
|
||||
use Psr\Http\Client\ClientExceptionInterface;
|
||||
|
||||
class email implements email_i
|
||||
{
|
||||
@@ -24,9 +42,9 @@ class email implements email_i
|
||||
{
|
||||
if ($test_recipient) {
|
||||
try {
|
||||
$this->sendEmail($test_recipient, 'Test email', 'This is a test email');
|
||||
$this->sendEmail($test_recipient, 'Test recipient', 'Test email', 'This is a test email');
|
||||
return 'Email sent successfully to ' . $test_recipient;
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
return 'Email error: ' . $e->getMessage();
|
||||
}
|
||||
} else {
|
||||
@@ -34,28 +52,121 @@ class email implements email_i
|
||||
}
|
||||
}
|
||||
|
||||
private function sendEmail($to, $subject, $message): void
|
||||
/**
|
||||
* Send an email using the preferred email service
|
||||
* @param string $to Email address to send the email to
|
||||
* @param string $recipient_name Name of the recipient
|
||||
* @param string $subject Subject of the email
|
||||
* @param string $message Message of the email
|
||||
* @throws Exception If an error occurs while sending the email
|
||||
*/
|
||||
public function sendEmail(string $to, string $recipient_name, string $subject, string $message, string $references = null): void
|
||||
{
|
||||
// Send POST request to email service
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, 'https://maintenancemode.cloud/mailer.php');
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
// Add the data to the request
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, [
|
||||
'recipient' => $to,
|
||||
'subject' => $subject,
|
||||
'message' => $message,
|
||||
]);
|
||||
// Return the response instead of outputting it
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
// Execute the POST request
|
||||
$response = curl_exec($ch);
|
||||
// Close cURL resource
|
||||
curl_close($ch);
|
||||
// Check for errors
|
||||
if ($response === false) {
|
||||
throw new \Exception('Curl error: ' . curl_error($ch));
|
||||
if ($this->config->mailersend_enabled->getVariableValue()) {
|
||||
try {
|
||||
// Generate HTML email
|
||||
$html = self::generateHtmlHeader();
|
||||
// Add email content
|
||||
$html .= $message;
|
||||
// Add email footer
|
||||
$html .= self::generateHtmlFooter();
|
||||
$this->sendEmailMailerSend($to, $recipient_name, $subject, $message, $html, $references);
|
||||
} catch (JsonException|MailerSendException|ClientExceptionInterface $e) {
|
||||
throw new Exception('Error sending email: ' . $e->getMessage());
|
||||
}
|
||||
} else {
|
||||
$this->sendEmailDefault($to, $subject, $message);
|
||||
}
|
||||
}
|
||||
|
||||
private static function generateHtmlHeader(): false|string
|
||||
{
|
||||
$email_template_head = (new email_template_head())->generate_html();
|
||||
$email_template_header = (new email_template_header())->generate_html();
|
||||
return "
|
||||
<!DOCTYPE html>
|
||||
<html lang='da'>
|
||||
<head>
|
||||
$email_template_head
|
||||
</head>
|
||||
<body>
|
||||
$email_template_header";
|
||||
}
|
||||
|
||||
private static function generateHtmlFooter(): string
|
||||
{
|
||||
$email_template_footer = (new email_template_footer())->generate_html();
|
||||
return "
|
||||
$email_template_footer
|
||||
</body>
|
||||
</html>";
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ClientExceptionInterface
|
||||
* @throws JsonException
|
||||
* @throws MailerSendAssertException
|
||||
* @throws MailerSendException
|
||||
*/
|
||||
private function sendEmailMailerSend(string $to, string $recipient_name, string $subject, string $message, string $html = null, string $references = null): void
|
||||
{
|
||||
// Send POST request to email service
|
||||
$mailersend = new MailerSend(['api_key' => $this->config->mailersend_api_key->getVariableValue()]);
|
||||
|
||||
$recipients = [
|
||||
new Recipient($to, $recipient_name)
|
||||
];
|
||||
|
||||
$emailParams = (new EmailParams())
|
||||
->setFrom($this->config->smtp_from->getVariableValue())
|
||||
->setFromName($this->config->smtp_from_name->getVariableValue())
|
||||
->setRecipients($recipients)
|
||||
->setSubject($subject)
|
||||
->setHtml($html ?? $message)
|
||||
->setReplyTo($this->config->smtp_reply_to->getVariableValue())
|
||||
->setReplyToName($this->config->smtp_reply_to_name->getVariableValue());
|
||||
|
||||
if ($references) {
|
||||
$emailParams->setHeaders([
|
||||
new Header('References', $references)
|
||||
]);
|
||||
}
|
||||
$mailersend->email->send($emailParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an email using the default SMTP service
|
||||
* @param string $to Email address to send the email to
|
||||
* @param string $subject Subject of the email
|
||||
* @param string $message Message of the email
|
||||
* @throws Exception If an error occurs while sending the email
|
||||
*/
|
||||
private function sendEmailDefault(string $to, string $subject, string $message): void
|
||||
{
|
||||
// Send email using default SMTP service
|
||||
throw new Exception('Default SMTP service not implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MailerSendException
|
||||
* @throws ClientExceptionInterface
|
||||
* @throws JsonException
|
||||
* @throws MailerSendAssertException
|
||||
*/
|
||||
public function sendStripeInvoiceEmail(string $to, string|null $recipient_name, string $payment_link, $order_id): void
|
||||
{
|
||||
$recipient_name = $recipient_name ?? 'Kunde';
|
||||
$recipient_name = ucfirst($recipient_name);
|
||||
// Generate HTML email
|
||||
$html = self::generateHtmlHeader();
|
||||
// Add email content
|
||||
$html .= (new email_template_stripe_invoice(
|
||||
$order_id,
|
||||
$payment_link,
|
||||
$recipient_name
|
||||
))->generate_html();
|
||||
// Add email footer
|
||||
$html .= self::generateHtmlFooter();
|
||||
$this->sendEmailMailerSend($to, $recipient_name, 'Betalingslink for bestilling #' . $order_id, '', $html);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace email\config;
|
||||
|
||||
use Exception;
|
||||
use traits\module_config_variable;
|
||||
|
||||
class email_mailersend_api_key_c
|
||||
{
|
||||
use module_config_variable;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::setupConfigVariable(
|
||||
'Email',
|
||||
'mailersend_api_key',
|
||||
'string',
|
||||
false,
|
||||
null,
|
||||
'The API key for the MailerSend email service',
|
||||
'mlsn.7dd13651...',
|
||||
true,
|
||||
''
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace email\config;
|
||||
|
||||
use Exception;
|
||||
use traits\module_config_variable;
|
||||
|
||||
class email_mailersend_enabled_c
|
||||
{
|
||||
use module_config_variable;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::setupConfigVariable(
|
||||
'Email',
|
||||
'mailersend_enabled',
|
||||
'bool',
|
||||
true,
|
||||
null,
|
||||
'Whether the email service should use MailerSend for sending emails',
|
||||
'1',
|
||||
false,
|
||||
'false'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace email\config;
|
||||
|
||||
use Exception;
|
||||
use traits\module_config_variable;
|
||||
|
||||
class email_smtp_reply_to_c
|
||||
{
|
||||
use module_config_variable;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::setupConfigVariable(
|
||||
'Email',
|
||||
'smtp_reply_to',
|
||||
'string',
|
||||
true,
|
||||
null,
|
||||
'The email address to reply to',
|
||||
'user@example.com',
|
||||
false,
|
||||
''
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace email\config;
|
||||
|
||||
use Exception;
|
||||
use traits\module_config_variable;
|
||||
|
||||
class email_smtp_reply_to_name_c
|
||||
{
|
||||
use module_config_variable;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::setupConfigVariable(
|
||||
'Email',
|
||||
'smtp_reply_to_name',
|
||||
'string',
|
||||
true,
|
||||
null,
|
||||
'The name to reply to',
|
||||
'Company Name Support',
|
||||
false,
|
||||
''
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace email;
|
||||
/** Universal */
|
||||
require_once WD . '/modules/email/config/email_enabled_c.php';
|
||||
require_once WD . '/modules/email/config/email_smtp_from_c.php';
|
||||
require_once WD . '/modules/email/config/email_smtp_from_name_c.php';
|
||||
require_once WD . '/modules/email/config/email_smtp_reply_to_c.php';
|
||||
require_once WD . '/modules/email/config/email_smtp_reply_to_name_c.php';
|
||||
|
||||
/** SMTP */
|
||||
require_once WD . '/modules/email/config/email_smtp_encryption_c.php';
|
||||
require_once WD . '/modules/email/config/email_smtp_host_c.php';
|
||||
require_once WD . '/modules/email/config/email_smtp_password_c.php';
|
||||
require_once WD . '/modules/email/config/email_smtp_port_c.php';
|
||||
require_once WD . '/modules/email/config/email_smtp_username_c.php';
|
||||
require_once WD . '/modules/email/config/email_smtp_from_c.php';
|
||||
require_once WD . '/modules/email/config/email_smtp_from_name_c.php';
|
||||
/** Mailersend */
|
||||
require_once WD . '/modules/email/config/email_mailersend_enabled_c.php';
|
||||
require_once WD . '/modules/email/config/email_mailersend_api_key_c.php';
|
||||
|
||||
use email\config\email_enabled_c;
|
||||
use email\config\email_mailersend_api_key_c;
|
||||
use email\config\email_mailersend_enabled_c;
|
||||
use email\config\email_smtp_encryption_c;
|
||||
use email\config\email_smtp_from_c;
|
||||
use email\config\email_smtp_from_name_c;
|
||||
use email\config\email_smtp_host_c;
|
||||
use email\config\email_smtp_password_c;
|
||||
use email\config\email_smtp_port_c;
|
||||
use email\config\email_smtp_reply_to_c;
|
||||
use email\config\email_smtp_reply_to_name_c;
|
||||
use email\config\email_smtp_username_c;
|
||||
use traits\module_config_t;
|
||||
|
||||
@@ -72,6 +84,29 @@ class email_c
|
||||
*/
|
||||
public email_smtp_from_name_c $smtp_from_name;
|
||||
|
||||
/**
|
||||
* The status of Mailersend, whether it is enabled or not
|
||||
* @var email_mailersend_enabled_c
|
||||
*/
|
||||
public email_mailersend_enabled_c $mailersend_enabled;
|
||||
|
||||
/**
|
||||
* The API key for the Mailersend email service
|
||||
* @var email_mailersend_api_key_c
|
||||
*/
|
||||
public email_mailersend_api_key_c $mailersend_api_key;
|
||||
|
||||
/**
|
||||
* The email address to reply to
|
||||
* @var email_smtp_reply_to_c The email address to reply to
|
||||
*/
|
||||
public email_smtp_reply_to_c $smtp_reply_to;
|
||||
/**
|
||||
* The name to reply to
|
||||
* @var email_smtp_reply_to_name_c The name to reply to
|
||||
*/
|
||||
public email_smtp_reply_to_name_c $smtp_reply_to_name;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
@@ -84,7 +119,11 @@ class email_c
|
||||
email_smtp_password_c::class,
|
||||
email_smtp_encryption_c::class,
|
||||
email_smtp_from_c::class,
|
||||
email_smtp_from_name_c::class
|
||||
email_smtp_from_name_c::class,
|
||||
email_mailersend_enabled_c::class,
|
||||
email_mailersend_api_key_c::class,
|
||||
email_smtp_reply_to_c::class,
|
||||
email_smtp_reply_to_name_c::class
|
||||
]);
|
||||
$this->enabled = new email_enabled_c();
|
||||
$this->smtp_host = new email_smtp_host_c();
|
||||
@@ -94,6 +133,10 @@ class email_c
|
||||
$this->smtp_encryption = new email_smtp_encryption_c();
|
||||
$this->smtp_from = new email_smtp_from_c();
|
||||
$this->smtp_from_name = new email_smtp_from_name_c();
|
||||
$this->mailersend_enabled = new email_mailersend_enabled_c();
|
||||
$this->mailersend_api_key = new email_mailersend_api_key_c();
|
||||
$this->smtp_reply_to = new email_smtp_reply_to_c();
|
||||
$this->smtp_reply_to_name = new email_smtp_reply_to_name_c();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace email\helpers;
|
||||
|
||||
trait email_template
|
||||
{
|
||||
protected string $subject;
|
||||
|
||||
abstract function generate_html(): string;
|
||||
|
||||
abstract function generate_text(): string;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace email\templates;
|
||||
|
||||
use email\helpers\email_template;
|
||||
|
||||
class email_template_footer
|
||||
{
|
||||
use email_template;
|
||||
|
||||
public function generate_text(): string
|
||||
{
|
||||
return "Truckwash ApS | CVR: 41004355 | https://truckwash.dk | Send os en email på cph@truckwash.dk - Ring til os på (+45) 43 71 78 86";
|
||||
}
|
||||
|
||||
public function generate_html(): string
|
||||
{
|
||||
ob_start();
|
||||
# Start of the html
|
||||
?>
|
||||
|
||||
<!-- Footer -->
|
||||
<br><br>
|
||||
<div style="max-width: 600px;">
|
||||
<img src="https://usercontent.one/wp/www.truckwash.dk/wp-content/uploads/2021/04/truckwash-banner-png.png"
|
||||
alt="Truck Wash logo" style="width: 25%; height: auto; display: block; margin: 0 auto;">
|
||||
<p style="text-align: center;"><a href="https://truckwash.dk/">Truckwash ApS</a> | <a
|
||||
href="https://datacvr.virk.dk/enhed/virksomhed/41004355"> CVR: 41004355</a> | <a
|
||||
href="https://truckwash.dk/">https://truckwash.dk</a></p>
|
||||
<p style="text-align: center;"><a href="mailto:cph@truckwash.dk"
|
||||
style="color: black; text-decoration: none;">Send os en email på
|
||||
cph@truckwash.dk</a> - <a href="tel:+4543717886" style="color: black; text-decoration: none;">Ring
|
||||
til os på (+45) 43 71 78 86</a></p>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
# End of the html
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace email\templates;
|
||||
|
||||
use email\helpers\email_template;
|
||||
|
||||
class email_template_head
|
||||
{
|
||||
use email_template;
|
||||
|
||||
public function generate_text(): string
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
public function generate_html(): string
|
||||
{
|
||||
ob_start();
|
||||
# Start of the html
|
||||
?>
|
||||
<!-- Styles -->
|
||||
<style>
|
||||
.email-template {
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background-color: #f9f9f9;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
.email-template h1 {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.email-template p {
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php
|
||||
# End of the html
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace email\templates;
|
||||
|
||||
use email\helpers\email_template;
|
||||
|
||||
class email_template_header
|
||||
{
|
||||
use email_template;
|
||||
|
||||
public function generate_text(): string
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
public function generate_html(): string
|
||||
{
|
||||
ob_start();
|
||||
# Start of the html
|
||||
?>
|
||||
|
||||
<!-- Logo -->
|
||||
<div style="max-width: 600px;">
|
||||
<img src="https://usercontent.one/wp/www.truckwash.dk/wp-content/uploads/2021/04/truckwash-banner-png.png"
|
||||
alt="Truck Wash logo"
|
||||
style="width: 100%; max-width: 600px; height: auto; display: block; margin: 0 auto;">
|
||||
</div>
|
||||
|
||||
<?php
|
||||
# End of the html
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace email\templates;
|
||||
|
||||
use email\helpers\email_template;
|
||||
|
||||
class email_template_stripe_invoice
|
||||
{
|
||||
use email_template;
|
||||
|
||||
protected int $order_id;
|
||||
protected string $stripe_payment_link;
|
||||
protected string $name;
|
||||
|
||||
public function __construct(int $order_id, string $stripe_payment_link, string $name)
|
||||
{
|
||||
$this->order_id = $order_id;
|
||||
$this->stripe_payment_link = $stripe_payment_link;
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function generate_text(): string
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
public function generate_html(): string
|
||||
{
|
||||
ob_start();
|
||||
# Start of the html
|
||||
?>
|
||||
|
||||
<!-- Email template -->
|
||||
<p>Kære <?= $this->name ?>,</p>
|
||||
<p>Tak for din bestilling hos Truck Wash. Vi har sendt dig en faktura på Stripe.
|
||||
Du kan betale fakturaen ved at klikke på linket nedenfor:</p>
|
||||
<p><a href="<?= $this->stripe_payment_link ?>">Betal faktura for ordre <?= $this->order_id ?></a></p>
|
||||
<!-- End of the email template -->
|
||||
|
||||
<?php
|
||||
# End of the html
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
@@ -338,6 +338,4 @@ class orders_o extends db
|
||||
{
|
||||
// Since the orders object is not cached, there is no need to invalidate the cache
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace routes;
|
||||
|
||||
use classes\authentication;
|
||||
use classes\email;
|
||||
use classes\response;
|
||||
use classes\router;
|
||||
use classes\stripe;
|
||||
@@ -94,6 +95,13 @@ class moduleStripeRoute
|
||||
);
|
||||
// Set the order stripe invoice details
|
||||
$order->setStripeInvoicing($result->id, (string)self::fromRequest('email'), $result->url);
|
||||
$email = new email();
|
||||
$email->sendStripeInvoiceEmail(
|
||||
(string)self::fromRequest('email'),
|
||||
null,
|
||||
$result->url,
|
||||
(int)self::fromRequest('order_id')
|
||||
);
|
||||
// Return the result
|
||||
$response->success((object)$result);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user