Skip to content

Commit 5aa6870

Browse files
Refactor socket handling & mailbox … and add tests!
1 parent 5a5305f commit 5aa6870

File tree

133 files changed

+5516
-1057
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

133 files changed

+5516
-1057
lines changed

.env

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
## Log levels:
2+
# - Debug
3+
# - Info
4+
# - Notice
5+
# - Warning
6+
# - Error
7+
# - Critical
8+
# - Alert
9+
# - Emergency
10+
SMTP_LOG_LEVEL=debug
11+
SMTP_LOG_FILE="%kernel.project_dir%/var/log/smtp.log"
12+
SMTP_SPOOL_DIR="%kernel.project_dir%/var/spool"
13+
HTTP_LOG_LEVEL=debug
14+
HTTP_LOG_FILE="%kernel.project_dir%/var/log/http.log"

.env.test

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
SMTP_LOG_LEVEL=debug
2+
SMTP_LOG_FILE="%kernel.project_dir%/var/test/smtp.log"
3+
SMTP_SPOOL_DIR="%kernel.project_dir%/var/test/spool"
4+
HTTP_LOG_LEVEL=debug
5+
HTTP_LOG_FILE="%kernel.project_dir%/var/test/http.log"

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/vendor/
33

44
/composer.lock
5+
/.env.local
56
/.php-cs-fixer.php
67
/.php-cs-fixer.cache
78
/phpunit.xml

.php-cs-fixer.dist.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@
1313
'@PhpCsFixer:risky' => true,
1414
])
1515
->in('src')
16+
->in('tests')
1617
;

README.md

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
SMTP Development Server
22
=======================
33

4-
A simple and very fake SMTP server for development/testing purposes.
4+
**FOR USE IN DEVELOPMENT ENVIRONMENTS ONLY**
55

6-
Now even with a HTTP server to provide a read-only mail client for messages received. Because, why not.
6+
A simple and very fake SMTP server for development/testing purposes. Because, why not.
7+
8+
**Features**
9+
- SMTP server that can accept & store valid RFC822/RFC2822 email
10+
- HTTP server/site as a client interface to the messages received
11+
12+
**WARNING: Do not expose running server ports to open networks and do not run as
13+
`root` or an admin user! There are ZERO security features built into these
14+
servers.**
715

816
Installation
917
------------
@@ -20,20 +28,53 @@ As a development dependency for your project:
2028
$ composer require --dev camelot/smtp-dev-server
2129
```
2230

31+
Configuration
32+
-------------
33+
34+
Configuration is handled via environment variables.
35+
36+
```shell
37+
SMTP_LOG_LEVEL=debug
38+
SMTP_LOG_FILE="/path/to/smtp.log"
39+
SMTP_SPOOL_DIR="/path/to/spool"
40+
HTTP_LOG_LEVEL=debug
41+
HTTP_LOG_FILE="/path/to/http.log"
42+
```
43+
44+
See the `.env` file in this directory for an example if you're cloning this
45+
repository, you can create a `.env.local` file to override any of the values in
46+
the `.env` file.
47+
2348
Use
2449
---
2550

51+
Both servers have two output targets, console and PSR logger.
52+
53+
Console output levels are managed by passing `-v`, `-vv`, or `-vvv` as options
54+
on the command line.
55+
56+
Logger output is managed via environment variables that are used internally to
57+
configure the loggers.
58+
59+
For example:
60+
```
61+
$ SMTP_LOG_LEVEL=debug vendor/bin/smtp-dev-server -vvv
62+
```
63+
2664
### Server
2765

66+
![image](https://user-images.githubusercontent.com/1427081/194073098-e655ea46-bda4-4c63-8d7e-c193f4636a82.png)
67+
2868
To start the server, simply run:
2969

3070
```console
3171
$ vendor/bin/smtp-dev-server
3272
```
3373

34-
This will output all incoming request data to STDOUT.
74+
This will output internal information to STDOUT. You can specify verbosity with
75+
the command options below.
3576

36-
**NOTE:** Currently the server will also log transactions to `./var/log/smtp.log`
77+
Server can be stopped by sending a signal, e.g. `CTRL+C`.
3778

3879
#### Arguments
3980

@@ -44,22 +85,28 @@ This will output all incoming request data to STDOUT.
4485
#### Options
4586

4687
```
47-
-i, --ip=IP TCP/IP address [default: "127.0.0.1"]
48-
-p, --port=PORT Port [default: 2525]
49-
-h, --help Show help
88+
-i, --ip=IP TCP/IP address [default: "127.0.0.1"]
89+
-p, --port=PORT Port to listen on [default: 2525]
90+
-r, --retries=RETRIES Number of times to retry connecting to the server socket address if it is currently in use [default: 10]
91+
-h, --help Show help
92+
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
5093
```
5194

5295
### Client
5396

97+
![image](https://user-images.githubusercontent.com/1427081/194073411-604cb0b9-0901-48ee-ae0a-86459394ae3c.png)
98+
![image](https://user-images.githubusercontent.com/1427081/194208872-28f7b627-846a-43ce-81d3-52c6c0a3b90d.png)
99+
54100
To start the server, simply run:
55101

56102
```console
57103
$ vendor/bin/smtp-dev-client
58104
```
59105

60-
This will output all incoming request data to STDOUT.
106+
This will output internal information to STDOUT. You can specify verbosity with
107+
the command options below.
61108

62-
**NOTE:** Currently the server will also log transactions to `./var/log/http.log`
109+
Server can be stopped by sending a signal, e.g. `CTRL+C`.
63110

64111
#### Arguments
65112

@@ -70,9 +117,11 @@ This will output all incoming request data to STDOUT.
70117
#### Options
71118

72119
```
73-
-i, --ip=IP TCP/IP address [default: "127.0.0.1"]
74-
-p, --port=PORT Port [default: 2580]
75-
-h, --help Show help
120+
-i, --ip=IP TCP/IP address [default: "127.0.0.1"]
121+
-p, --port=PORT Port to listen on [default: 2580]
122+
-r, --retries=RETRIES Number of times to retry connecting to the server socket address if it is currently in use [default: 10]
123+
-h, --help Show help
124+
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
76125
```
77126

78127
Open (default) `http://127.0.0.1:2580` to view & manage messages received by the SMTP server component.

bin/app.php

Lines changed: 0 additions & 46 deletions
This file was deleted.

bin/smtp-dev-client

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,27 @@
22
<?php
33

44
use Camelot\SmtpDevServer\Command\HttpServerCommand;
5+
use Camelot\SmtpDevServer\DependencyInjection\Kernel;
6+
use Symfony\Component\Console\Command\HelpCommand;
57
use Symfony\Component\Console\Input\ArgvInput;
68
use Symfony\Component\Console\Output\ConsoleOutput;
7-
use Symfony\Component\DependencyInjection\Container;
89

9-
$run = function (): void {
10-
$builder = require_once __DIR__ . '/app.php';
11-
/** @var Container $container */
12-
$container = $builder();
13-
$command = $container->get(HttpServerCommand::class);
14-
$command->run(new ArgvInput(), new ConsoleOutput());
10+
$run = function (): int {
11+
require_once dirname(__DIR__) . '/config/bootstrap.php';
12+
$kernel = new Kernel('dev', true);
13+
$kernel->boot();
14+
$command = $kernel->getContainer()->get(HttpServerCommand::class);
15+
16+
$input = new ArgvInput(null, $command->getDefinition());
17+
if ($input->getOption('help')) {
18+
$help = new HelpCommand();
19+
$help->setCommand($command);
20+
21+
return $help->run($input, new ConsoleOutput());
22+
}
23+
24+
return $command->run(new ArgvInput(), new ConsoleOutput());
1525
};
1626

17-
$run();
27+
return $run();
1828

bin/smtp-dev-server

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,26 @@
22
<?php
33

44
use Camelot\SmtpDevServer\Command\SmtpServerCommand;
5+
use Camelot\SmtpDevServer\DependencyInjection\Kernel;
6+
use Symfony\Component\Console\Command\HelpCommand;
57
use Symfony\Component\Console\Input\ArgvInput;
68
use Symfony\Component\Console\Output\ConsoleOutput;
7-
use Symfony\Component\DependencyInjection\Container;
89

9-
$run = function (): void {
10-
$builder = require_once __DIR__ . '/app.php';
11-
/** @var Container $container */
12-
$container = $builder();
13-
$command = $container->get(SmtpServerCommand::class);
14-
$command->run(new ArgvInput(), new ConsoleOutput());
10+
$run = function (): int {
11+
require_once dirname(__DIR__) . '/config/bootstrap.php';
12+
$kernel = new Kernel('dev', true);
13+
$kernel->boot();
14+
$command = $kernel->getContainer()->get(SmtpServerCommand::class);
15+
16+
$input = new ArgvInput(null, $command->getDefinition());
17+
if ($input->getOption('help')) {
18+
$help = new HelpCommand();
19+
$help->setCommand($command);
20+
21+
return $help->run($input, new ConsoleOutput());
22+
}
23+
24+
return $command->run(new ArgvInput(), new ConsoleOutput());
1525
};
1626

17-
$run();
27+
return $run();

composer.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,26 @@
1313
"minimum-stability": "stable",
1414
"require": {
1515
"php": ">=8.1",
16+
"ext-pcntl": "*",
17+
"ext-sockets": "*",
1618
"monolog/monolog": "^3.0",
1719
"php-mime-mail-parser/php-mime-mail-parser": "^7.1",
1820
"psr/log": "^2.0 || ^3.0",
1921
"symfony/config": "^6.0",
2022
"symfony/console": "^6.0",
2123
"symfony/dependency-injection": "^6.0",
24+
"symfony/dotenv": "^6.0",
2225
"symfony/event-dispatcher": "^6.0",
23-
"symfony/http-foundation": "^6.0",
26+
"symfony/finder": "^6.0",
2427
"symfony/http-kernel": "^6.0",
2528
"symfony/routing": "^6.0",
29+
"symfony/stopwatch": "^6.0",
2630
"twig/twig": "^3.4"
2731
},
2832
"require-dev": {
2933
"camelot/coding-style": "^3.0",
3034
"friendsofphp/php-cs-fixer": "^3.11",
35+
"symfony/mailer": "^6.0",
3136
"phpunit/phpunit": "^9.5",
3237
"symfony/phpunit-bridge": "^6.0"
3338
},
@@ -42,6 +47,7 @@
4247
}
4348
},
4449
"bin": [
50+
"bin/smtp-dev-client",
4551
"bin/smtp-dev-server"
4652
]
4753
}

config/bootstrap.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Symfony\Component\Dotenv\Dotenv;
6+
7+
if (is_file(dirname(__DIR__) . '/vendor/autoload.php')) {
8+
$projectDir = dirname(__DIR__);
9+
require_once $projectDir . '/vendor/autoload.php';
10+
} elseif (is_file(dirname(__DIR__, 3) . '/autoload.php')) {
11+
$projectDir = dirname(__DIR__, 3);
12+
require_once $projectDir . '/autoload.php';
13+
} else {
14+
throw new LogicException('Composer autoload is missing. Try running "composer install".');
15+
}
16+
17+
(new DotEnv())->bootEnv("{$projectDir}/.env");

0 commit comments

Comments
 (0)