Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .github/FUNDING.yml

This file was deleted.

9 changes: 5 additions & 4 deletions .github/workflows/phpunit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ jobs:
strategy:
matrix:
php-version:
- "8.6"
- "8.5"
- "8.4"
- "8.3"

steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v7
- run: composer install
- run: composer test

Expand All @@ -34,20 +35,20 @@ jobs:
# for github/codeql-action/upload-sarif to upload SARIF results
security-events: write
container:
image: byjg/php:8.4-cli
image: byjg/php:8.5-cli
options: --user root --privileged

steps:
- name: Git checkout
uses: actions/checkout@v4
uses: actions/checkout@v7

- name: Composer
run: composer install

- name: Psalm
# Note: Ignoring error code 2, which just signals that some
# flaws were found, not that Psalm itself failed to run.
run: ./vendor/bin/psalm
run: ./vendor/bin/psalm.phar
--show-info=true
--report=psalm-results.sarif || [ $? = 2 ]

Expand Down
154 changes: 154 additions & 0 deletions CHANGELOG-6.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# Changelog for Version 6.0

Version 6.0 represents a major update to the MailWrapper library, focusing on improved type safety, modern PHP standards, and enhanced null-safety checks. This release includes several breaking changes that require attention when upgrading from version 5.x.

## New Features

### Enhanced Type Safety
- Added comprehensive type declarations throughout the codebase, including parameter types, return types, and property types
- Introduced PHPDoc annotations with generic types (e.g., `@var array<string, class-string<MailWrapperInterface>>`)
- Added `#[\Override]` attributes to ensure proper method inheritance

### Improved Null Safety
- Refactored mail wrappers with null-coalescing operators for safer null handling
- Enhanced null-safety checks in `PHPMailerWrapper`, `AmazonSesWrapper`, and `MailgunApiWrapper`
- Improved handling of optional URI components (username, password, host, port, scheme)

### Documentation Improvements
- Comprehensive Docusaurus-compatible documentation structure
- New detailed documentation pages:
- Getting Started guide
- Envelope configuration guide
- Connection Strings reference
- Mailer Factory usage
- Attachments handling
- Custom Wrappers implementation
- Exception handling guide

### Testing & CI Enhancements
- Updated PHPUnit configuration with improved structure and container options
- Enhanced GitHub Actions workflow configuration
- Added `composer test` and `composer psalm` scripts for easier development workflow

## Breaking Changes

| Aspect | Before (5.x) | After (6.0) | Description |
|--------|--------------|-------------|-------------|
| **PHP Version** | `>=8.1 <8.4` | `>=8.3 <8.6` | Minimum PHP version increased to 8.3, added support for PHP 8.4 and 8.5 |
| **byjg/convert** | `^5.0` | `^6.0` | Dependency upgraded to major version 6 |
| **byjg/webrequest** | `^5.0` | `^6.0` | Dependency upgraded to major version 6 |
| **PHPUnit** | `^9.6` | `^10.5\|^11.5` | Dev dependency upgraded to PHPUnit 10 or 11 |
| **Psalm** | `^5.9` | `^5.9\|^6.13` | Dev dependency supports Psalm 6 |
| **Test Files** | `*WrapperTest.php` | `*TestWrapper.php` | Test class files renamed from suffix pattern |
| **MailerFactory::create()** | `string $connection` | `UriInterface\|string $connection` | Now accepts PSR-7 UriInterface in addition to string |
| **MailerFactory::registerMailer()** | No return type | `void` return type | Explicit void return type added |
| **Type Strictness** | Relaxed null handling | Strict null-safety | All wrapper methods now use null-safe operators (`?->`) and null coalescing (`??`) |

### Additional API Changes

- **MailerFactory::registerMailer()**: Parameter now properly typed as `class-string<MailWrapperInterface>`
- **PHPMailerWrapper**: URI property access now uses null-safe operators throughout
- **Envelope**: Minor adjustments for stricter type checking
- **Test namespace**: Test classes use proper PSR-4 autoloading with `Tests\` namespace

## Path to Upgrade from 5.x to 6.0

### Step 1: Check PHP Version
Ensure your environment is running PHP 8.3 or higher:
```bash
php --version
```

If you're running PHP 8.1 or 8.2, you must upgrade to PHP 8.3+ before upgrading to MailWrapper 6.0.

### Step 2: Update Dependencies
Update your `composer.json`:
```json
{
"require": {
"byjg/mailwrapper": "^6.0"
}
}
```

Then run:
```bash
composer update byjg/mailwrapper
```

This will automatically update the required dependencies (`byjg/convert` and `byjg/webrequest` to version 6).

### Step 3: Update Dev Dependencies (if applicable)
If you have PHPUnit or Psalm in your project:
```bash
composer update phpunit/phpunit vimeo/psalm --with-dependencies
```

### Step 4: Review Custom Implementations
If you have custom mail wrappers that implement `MailWrapperInterface`:

1. Add proper type declarations to all methods
2. Add `#[\Override]` attribute to interface methods
3. Ensure null-safety in URI handling:
```php
// Before
$host = $this->uri->getHost();

// After
$host = $this->uri?->getHost() ?? 'default-host';
```

### Step 5: Update MailerFactory Usage (Optional)
If you pass URI objects to `MailerFactory::create()`, ensure they implement `Psr\Http\Message\UriInterface`:
```php
use ByJG\Util\Uri;
use ByJG\Mail\MailerFactory;

// Both styles now work:
$mailer1 = MailerFactory::create('smtp://user:pass@smtp.example.com');
$mailer2 = MailerFactory::create(new Uri('smtp://user:pass@smtp.example.com'));
```

### Step 6: Run Tests
After upgrading, run your test suite to ensure compatibility:
```bash
vendor/bin/phpunit
```

If you use Psalm:
```bash
vendor/bin/psalm
```

### Step 7: Update Test Files (if extending MailWrapper tests)
If your project extends any MailWrapper test classes, note the renamed files:
- `BaseWrapperTest.php` → `BaseTestWrapper.php`
- `PHPMailerWrapperTest.php` → `PHPMailerTestWrapper.php`
- `AmazonSesWrapperTest.php` → `AmazonSesTestWrapper.php`
- `MailgunWrapperTest.php` → `MailgunTestWrapper.php`
- `FakeSenderWrapperTest.php` → `FakeSenderTestWrapper.php`

## Bug Fixes

- Fixed Psalm-related type issues for improved static analysis
- Improved null-safety checks preventing potential null pointer exceptions
- Enhanced SMTP authentication handling with proper null checks
- Fixed potential issues with missing URI components in wrapper configurations

## Notes

- All existing connection string formats remain compatible
- No changes to the public API for `Envelope` class usage
- Wrapper registration and usage patterns remain the same
- Documentation now available in comprehensive Docusaurus format

## Migration Support

If you encounter issues during migration, please:
1. Review the new documentation in the `docs/` directory
2. Check the updated examples in the README
3. File an issue on GitHub: https://github.com/byjg/php-mailwrapper/issues

---

**Full Changelog**: https://github.com/byjg/php-mailwrapper/compare/5.0.2...6.0
60 changes: 60 additions & 0 deletions CHANGELOG-7.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Changelog - Version 7.0

> **Status: in development.** This document tracks changes landing on the `7.0` branch.
> Nothing here is released yet, and the contents may still change.

## Breaking Changes

- None.

## New Features

- `FakeSenderWrapper` keeps every envelope it is given. `FakeSenderWrapper::getSent()`
returns them, oldest first, and `FakeSenderWrapper::clear()` forgets them, so a test can
check what the application would have sent. Sending still does nothing and always
succeeds.

## Requirements

- PHP 8.3, 8.4, 8.5 and 8.6 are now supported: `"php": ">=8.3 <8.7"`.
The previous `<8.6` upper bound excluded PHP 8.6, since `<8.6` is exclusive.

### ByJG dependencies

- `byjg/convert` is now `^7.0`.
- `byjg/webrequest` is now `^7.0`.

While 7.0 is unreleased these resolve to `7.0.x-dev` from each component's
`7.0` branch, via `minimum-stability: dev` with `prefer-stable: true`.

## Toolchain

- PHPUnit updated to `^12.5`.
- Psalm is installed as `psalm/phar` instead of `vimeo/psalm`.

`vimeo/psalm` lists the PHP versions it supports and no published release includes
8.6, so as a dev dependency it made `composer install` fail on the 8.6 build job
before any test ran. `psalm/phar` requires only `php ^8.2` and bundles its own
dependencies, so it installs on every PHP version in the matrix and cannot conflict
with the project's. Psalm itself still refuses to *run* on 8.6, which is why the
Psalm job uses 8.5. `composer psalm` runs it.

- PHPUnit 13 is deliberately **not** used. It requires PHP `>=8.4.1`, breaking the
8.3 floor.

## Continuous Integration

- The build matrix now includes PHP 8.6.
- The Psalm job runs on PHP 8.5.

## Housekeeping

- `phpunit.xml.dist` renamed to `phpunit.xml`.
- The wrapper tests now run. They were named `*TestWrapper.php`, which PHPUnit's default
`Test.php` suffix skips, so the Amazon SES, FakeSender, Mailgun and PHPMailer tests had
not been running. They are renamed to `*WrapperTest.php`. The Amazon SES test, broken
unnoticed since `getSesClient()` gained its `SesClient` return type, now uses the SDK's
`Aws\MockHandler` instead of the `MockSender` stand-in, which is removed.
- `phpunit.xml` sets `ignoreIndirectDeprecations="true"`. PHP 8.6 deprecates `is` as a class
name, and `guzzlehttp/promises` (required by the AWS SDK) has a class called `Is`.
Deprecations raised inside this package's own `src/` still fail the suite.
19 changes: 6 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ A lightweight wrapper for sending email. The interface is totally decoupled from

[![Sponsor](https://img.shields.io/badge/Sponsor-%23ea4aaa?logo=githubsponsors&logoColor=white&labelColor=0d1117)](https://github.com/sponsors/byjg)
[![Build Status](https://github.com/byjg/php-mailwrapper/actions/workflows/phpunit.yml/badge.svg?branch=master)](https://github.com/byjg/php-mailwrapper/actions/workflows/phpunit.yml)
[![Opensource ByJG](https://img.shields.io/badge/opensource-byjg-success.svg)](http://opensource.byjg.com)
[![Opensource ByJG](https://img.shields.io/badge/opensource-byjg-success.svg)](https://opensource.byjg.com)
[![Install MCP Server](https://img.shields.io/badge/Install-MCP_Server-8A2BE2?logo=modelcontextprotocol&logoColor=white)](https://opensource.byjg.com/docs/ai/mcpserver-byjg-docs/)
[![GitHub source](https://img.shields.io/badge/Github-source-informational?logo=github)](https://github.com/byjg/php-mailwrapper/)
[![GitHub license](https://img.shields.io/github/license/byjg/php-mailwrapper.svg)](https://opensource.byjg.com/opensource/licensing.html)
[![GitHub license](https://img.shields.io/github/license/byjg/php-mailwrapper.svg)](https://opensource.byjg.com/license/)
[![GitHub release](https://img.shields.io/github/release/byjg/php-mailwrapper.svg)](https://github.com/byjg/php-mailwrapper/releases/)

## Available Wrappers
Expand All @@ -20,9 +21,9 @@ A lightweight wrapper for sending email. The interface is totally decoupled from
- **AWS SES** - Amazon Simple Email Service (using API directly)
- **Mailgun** - Mailgun API (using API directly)
- **SendMail** - PHP's built-in mail() function
- **FakeSender** - For testing (does nothing)
- **FakeSender** - For testing (sends nothing, keeps the envelopes for assertions)

## Install
## Installation

```shell
composer require "byjg/mailwrapper"
Expand Down Expand Up @@ -90,13 +91,5 @@ See [Connection Strings](docs/connection-strings.md) for detailed configuration
./vendor/bin/phpunit
```

## Dependencies

```mermaid
flowchart TD
byjg/mailwrapper --> byjg/convert
byjg/mailwrapper --> byjg/webrequest
```

----
[Open source ByJG](http://opensource.byjg.com)
[Open source ByJG](https://opensource.byjg.com)
12 changes: 6 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,20 @@
"prefer-stable": true,
"minimum-stability": "dev",
"require": {
"php": ">=8.3 <8.6",
"php": ">=8.3 <8.7",
"ext-curl": "*",
"byjg/convert": "^6.0",
"byjg/webrequest": "^6.0",
"byjg/convert": "^7.0",
"byjg/webrequest": "^7.0",
"aws/aws-sdk-php": "~3.20",
"phpmailer/phpmailer": ">=6.4.1"
},
"require-dev": {
"phpunit/phpunit": "^10.5|^11.5",
"vimeo/psalm": "^5.9|^6.13"
"phpunit/phpunit": "^12.5",
"psalm/phar": "^6.16"
},
"scripts": {
"test": "vendor/bin/phpunit",
"psalm": "vendor/bin/psalm --threads=1"
"psalm": "vendor/bin/psalm.phar"
},
"license": "MIT"
}
17 changes: 15 additions & 2 deletions docs/connection-strings.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ scheme://username:password@host:port
| sendmail | PHP's built-in mail() function | `sendmail://localhost` | SendMailWrapper |
| mailgun | Mailgun API | `mailgun://YOUR_API_KEY@YOUR_DOMAIN` | MailgunApiWrapper |
| ses | Amazon SES API | `ses://ACCESS_KEY_ID:SECRET_KEY@REGION` | AmazonSesWrapper |
| fakesender | Testing (does nothing) | `fakesender://localhost` | FakeSenderWrapper |
| fakesender | Testing (sends nothing) | `fakesender://localhost` | FakeSenderWrapper |

## Examples

Expand Down Expand Up @@ -106,4 +106,17 @@ $mailer = \ByJG\Mail\MailerFactory::create(
);
```

The FakeSender wrapper does nothing and always returns success. It's useful for testing without actually sending emails.
The FakeSender wrapper sends nothing and always returns success. It's useful for testing without actually sending emails.

It keeps every envelope it is given, so a test can check what would have been sent:

```php
use ByJG\Mail\Wrapper\FakeSenderWrapper;

FakeSenderWrapper::clear(); // forget earlier sends
$service->requestPasswordReset($email); // code under test sends through the mailer

$sent = FakeSenderWrapper::getSent(); // list<Envelope>, oldest first
$this->assertCount(1, $sent);
$this->assertEquals('Password Reset', $sent[0]->getSubject());
```
2 changes: 1 addition & 1 deletion docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ MailWrapper is organized into three main components:
- **AWS SES** - Amazon Simple Email Service (using API directly)
- **Mailgun** - Mailgun API
- **SendMail** - PHP's built-in mail() function
- **FakeSender** - For testing (does nothing)
- **FakeSender** - For testing (sends nothing, keeps the envelopes for assertions)

## Running Tests

Expand Down
3 changes: 3 additions & 0 deletions docs/mailer-factory.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,6 @@ if ($isTestEnvironment) {
$mailer = \ByJG\Mail\MailerFactory::create($productionConnection);
}
```

`FakeSenderWrapper::getSent()` returns the envelopes it was given, and `clear()` forgets them.
See [FakeSender](connection-strings.md#fakesender-testing).
21 changes: 0 additions & 21 deletions example.php

This file was deleted.

Loading
Loading