Skip to content

Commit 3e7e427

Browse files
committed
feat: initialize project
0 parents  commit 3e7e427

16 files changed

Lines changed: 2136 additions & 0 deletions

.gitignore

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Composer
2+
vendor/
3+
composer.lock
4+
auth.json
5+
6+
# Environment
7+
.env
8+
.env.*
9+
!.env.example
10+
11+
# IDEs & editors
12+
.idea/
13+
.vscode/
14+
!.vscode/settings.json
15+
!.vscode/tasks.json
16+
!.vscode/launch.json
17+
!.vscode/extensions.json
18+
.fleet/
19+
.nova/
20+
.zed/
21+
.phpactor.json
22+
*.swp
23+
*.swo
24+
*~
25+
*.sublime-*
26+
*.sublime-project
27+
*.sublime-workspace
28+
29+
# OS files
30+
.DS_Store
31+
Thumbs.db
32+
33+
# Testing & static analysis
34+
.phpunit.cache/
35+
.phpunit.result.cache
36+
.phpstan/
37+
coverage/
38+
39+
# Logs
40+
*.log

AGENTS.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Laravel Mailtrap Driver — Agent Guide
2+
3+
## Commands
4+
5+
```bash
6+
composer run check # lint → analyse → test (preferred)
7+
composer run test # PHPUnit with Clover + HTML coverage → coverage/
8+
composer run analyse # PHPStan level 8, --memory-limit=1G
9+
composer run format # Pint — modifies files in-place
10+
composer run lint # Pint --test — checks formatting without modifying
11+
```
12+
13+
**Coverage gotcha:** `composer run test` and `composer run check` both require a coverage driver (Xdebug or pcov). Without one, PHPUnit exits with error. For local runs:
14+
```bash
15+
vendor/bin/phpunit --no-coverage
16+
```
17+
18+
## Architecture
19+
20+
Four source files in `src/`, all under namespace `Ronald2Wing\LaravelMailtrap\`:
21+
22+
| File | Role |
23+
|------|------|
24+
| `MailtrapServiceProvider.php` | Registers the `mailtrap` transport. Reads from `services.mailtrap` by default; each mailer may override via `'config' => 'services.mailtrap.marketing'`. |
25+
| `MailtrapTransport.php` | Symfony `AbstractTransport`. POSTs to `apiUrl()` with JSON from `PayloadBuilder`. |
26+
| `PayloadBuilder.php` | Translates Symfony `Email` + `Envelope` into Mailtrap's JSON payload. Pure, no I/O. |
27+
| `MailtrapConfig.php` | Readonly value object — token, endpoint, optional inbox id, Guzzle options. Public constants: `SEND_ENDPOINT`, `BULK_ENDPOINT`, `SANDBOX_ENDPOINT`. Factory: `fromArray()`. |
28+
29+
### MailtrapConfig config mapping (`fromArray`)
30+
31+
| Config key (`services.mailtrap.*`) | Property | Notes |
32+
|------------------------------------|----------|-------|
33+
| `token` | `apiToken` | Required; must be non-empty |
34+
| `endpoint` | `endpoint` | Defaults to `SEND_ENDPOINT` |
35+
| `inbox_id` | `inboxId` | Required when endpoint is `SANDBOX_ENDPOINT` |
36+
| `http` | `httpOverrides` | Guzzle options; merged over `DEFAULT_HTTP_OPTIONS` (`connect_timeout: 10`, `timeout: 30`) |
37+
38+
### PayloadBuilder header handling
39+
40+
Two constants control Mailtrap-specific headers:
41+
42+
| Constant | Headers mapped | Value handling |
43+
|----------|---------------|----------------|
44+
| `MAILTRAP_STRING_HEADERS` | `X-Mailtrap-Category``category`, `X-Mailtrap-Template-Uuid``template_uuid` | Passed as-is (string) |
45+
| `MAILTRAP_JSON_HEADERS` | `X-Mailtrap-Template-Variables``template_variables`, `X-Mailtrap-Custom-Variables``custom_variables` | JSON-decoded to array |
46+
47+
Standard headers are defined in `RFC5322_HEADERS`. Both header constants feed `reservedHeaderNames()`, used by `extractForwardedHeaders()` to filter reserved headers out of the forwarded `headers` block. `extractReplyTo()` handles Reply-To separately. Both are merged in `build()`.
48+
49+
### Adding a new Mailtrap-specific header
50+
51+
1. Add an entry to `PayloadBuilder::MAILTRAP_STRING_HEADERS` or `PayloadBuilder::MAILTRAP_JSON_HEADERS` depending on whether the value needs JSON decoding.
52+
2. Done. `extractMailtrapHeaders` picks it up, `reservedHeaderNames` strips it from the forwarded headers block.
53+
54+
## Static Analysis
55+
56+
PHPStan runs at **level 8** with **no ignored errors** on both `src/` and `tests/`. Never add baseline entries or `@phpstan-ignore` comments.
57+
58+
## CI
59+
60+
CI (`php.yml`) runs **test → lint → analyse** (different order from `composer check` which is lint → analyse → test). It also runs `composer validate --strict`.
61+
62+
## Testing
63+
64+
- **Base classes**: `Orchestra\Testbench\TestCase` for container-aware tests; `PHPUnit\Framework\TestCase` for pure unit tests.
65+
- **HTTP mocking**: Guzzle `MockHandler` + `HandlerStack` with a history middleware.
66+
- **Reflection**: `extractMessageId` (private static) is tested via `invokeProtected` helper in `MailtrapTransportTest`.
67+
- `getEnvironmentSetUp()` configures `services.mailtrap`, `mail.default`, and `mail.from` for integration tests.
68+
69+
## Conventions
70+
71+
- `declare(strict_types=1)` in every file.
72+
- `composer.json` has `sort-packages: true` — Composer auto-sorts after `composer require`. Keep it valid for CI.
73+
- PHPDoc with `@param` array shapes on every public/protected method.

CHANGELOG.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [1.0.0] - 2025-11-11
9+
10+
### Added
11+
12+
- Initial release of Laravel Mailtrap Driver package.
13+
- Mailtrap Email Sending API transport via Symfony Mailer.
14+
- Text and HTML email support.
15+
- Multipart emails (both text and HTML).
16+
- File attachments (regular and inline).
17+
- CC and BCC recipients.
18+
- Custom headers and Reply-To (multiple addresses joined per RFC 5322).
19+
- Mailtrap categories via `X-Mailtrap-Category` header.
20+
- Template support via `X-Mailtrap-Template-Uuid`, `X-Mailtrap-Template-Variables`, and `X-Mailtrap-Custom-Variables` headers.
21+
- Sandbox, Bulk, and Transactional endpoints with `inbox_id` configuration.
22+
- HTTP client options via `http` config key (defaults: `connect_timeout: 10`, `timeout: 30`).
23+
- International character support (UTF-8).
24+
- PHP 8.3+, Laravel 10.x–13.x.
25+
- PHPStan level 8 with zero ignored errors.
26+
- Comprehensive test suite.
27+
- CI via GitHub Actions.

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) Ronald Wong <ronald2wing@gmail.com>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

0 commit comments

Comments
 (0)