Skip to content

Commit 71d207e

Browse files
author
Rico Kritz
committed
added tests for sending encrypted emails and ensure mailer and mime assertions can handle Message objects as well
1 parent 91442ce commit 71d207e

6 files changed

Lines changed: 104 additions & 2 deletions

File tree

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"symfony/yaml": "5.4.*"
3232
},
3333
"require-dev": {
34+
"ext-openssl": "*",
3435
"codeception/codeception": "^5.3",
3536
"codeception/module-asserts": "^3.2",
3637
"codeception/module-doctrine": "^3.3",

config/routes.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,8 @@
8888
$routes->add('send_email', '/send-email')
8989
->controller(App\Controller\SendEmailController::class)
9090
->methods(['GET']);
91+
92+
$routes->add('send_encrypted_email', '/send-encrypted-email')
93+
->controller(App\Controller\SendEncryptedEmailController::class)
94+
->methods(['GET']);
9195
};
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Controller;
6+
7+
use App\Entity\User;
8+
use App\Utils\Mailer;
9+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
10+
use Symfony\Component\HttpFoundation\Response;
11+
12+
final class SendEncryptedEmailController extends AbstractController
13+
{
14+
public function __construct(
15+
private readonly Mailer $mailer,
16+
) {
17+
}
18+
19+
public function __invoke(): Response
20+
{
21+
$this->mailer->sendEncryptedEmail((new User())->setEmail('jane_doe@example.com'));
22+
23+
return $this->json(['message' => 'Encrypted email sent successfully']);
24+
}
25+
}

src/Utils/Crypto.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Utils;
6+
7+
final readonly class Crypto
8+
{
9+
public function generateSslCertificate(): string
10+
{
11+
if (!extension_loaded('openssl')) {
12+
throw new \RuntimeException('OpenSSL extension is required.');
13+
}
14+
15+
$privateKey = openssl_pkey_new();
16+
$certSignRequest = openssl_csr_new([], $privateKey);
17+
$certificate = openssl_csr_sign($certSignRequest, null, $privateKey, 1);
18+
19+
$tmpDir = sys_get_temp_dir();
20+
$privateKeyPath = tempnam($tmpDir, 'pkey');
21+
$certificatePath = tempnam($tmpDir, 'cert');
22+
23+
if (!openssl_pkey_export_to_file($privateKey, $privateKeyPath, 'powercloud')) {
24+
throw new \RuntimeException('Private key generation failed: ' . openssl_error_string());
25+
}
26+
if (!openssl_x509_export_to_file($certificate, $certificatePath)) {
27+
throw new \RuntimeException('OpenSSL certificate generation failed: ' . openssl_error_string());
28+
}
29+
30+
register_shutdown_function(static function () use ($privateKeyPath, $certificatePath): void {
31+
unlink($privateKeyPath);
32+
unlink($certificatePath);
33+
});
34+
35+
return $certificatePath;
36+
}
37+
}

src/Utils/Mailer.php

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,16 @@
88
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
99
use Symfony\Component\Mailer\MailerInterface;
1010
use Symfony\Component\Mime\Address;
11+
use Symfony\Component\Mime\Crypto\SMimeEncrypter;
12+
use Symfony\Component\Mime\Email;
13+
use Symfony\Component\Mime\Message;
1114

1215
final readonly class Mailer
1316
{
14-
public function __construct(private MailerInterface $mailer)
15-
{
17+
public function __construct(
18+
private MailerInterface $mailer,
19+
private Crypto $crypto,
20+
) {
1621
}
1722

1823
public function sendConfirmationEmail(User $user): TemplatedEmail
@@ -30,4 +35,20 @@ public function sendConfirmationEmail(User $user): TemplatedEmail
3035

3136
return $email;
3237
}
38+
39+
public function sendEncryptedEmail(User $user): Message
40+
{
41+
$encrypter = new SMimeEncrypter($this->crypto->generateSslCertificate());
42+
43+
$email = (new Email())
44+
->from(new Address('jeison_doe@gmail.com', 'No Reply'))
45+
->to(new Address($user->getEmail()))
46+
->subject('Encrypted email')
47+
->text('Encrypted content');
48+
49+
$message = $encrypter->encrypt($email);
50+
$this->mailer->send($message);
51+
52+
return $message;
53+
}
3354
}

tests/Functional/IssuesCest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use App\Entity\User;
88
use App\Tests\Support\FunctionalTester;
99
use Doctrine\DBAL\Connection;
10+
use Symfony\Component\Mime\Message;
1011

1112
final class IssuesCest
1213
{
@@ -53,4 +54,17 @@ public function runSymfonyConsoleCommandIgnoresSpecificOptions(FunctionalTester
5354
$numRecords = $I->grabNumRecords(User::class);
5455
$I->assertSame(1, $numRecords);
5556
}
57+
58+
/**
59+
* @see https://github.com/Codeception/module-symfony/pull/232
60+
*/
61+
public function assertEncryptedEmailTests(FunctionalTester $I)
62+
{
63+
$I->amOnPage('/send-encrypted-email');
64+
$I->seeEmailIsSent(1);
65+
$I->assertEmailAddressContains('To', 'jane_doe@example.com');
66+
$I->assertEmailHeaderSame('To', 'jane_doe@example.com');
67+
$I->assertEmailHeaderSame('Subject', 'Encrypted email');
68+
$I->assertInstanceOf(Message::class, $I->grabLastSentEmail());
69+
}
5670
}

0 commit comments

Comments
 (0)