diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml
index 97f8b52..2b4481e 100644
--- a/.github/workflows/phpunit.yml
+++ b/.github/workflows/phpunit.yml
@@ -12,16 +12,19 @@ on:
jobs:
Build:
runs-on: 'ubuntu-latest'
- container: 'byjg/php:${{ matrix.php-version }}-cli'
+ container:
+ image: 'byjg/php:${{ matrix.php-version }}-cli'
+ options: --user root --privileged
strategy:
matrix:
php-version:
+ - "8.4"
- "8.3"
- "8.2"
- "8.1"
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- run: composer install
- run: ./vendor/bin/phpunit
diff --git a/.gitignore b/.gitignore
index 99c9f68..004001b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,6 @@ composer.lock
vendor
.idea
.phpunit.result.cache
+phpunit.coverage.xml
+phpunit.report.xml
+*.bak
diff --git a/.run/PHPUnit.run.xml b/.run/PHPUnit.run.xml
index f81c245..d5231dd 100644
--- a/.run/PHPUnit.run.xml
+++ b/.run/PHPUnit.run.xml
@@ -3,4 +3,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/.run/psalm.run.xml b/.run/psalm.run.xml
new file mode 100644
index 0000000..d9c1b61
--- /dev/null
+++ b/.run/psalm.run.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 429d85f..d3f10da 100644
--- a/README.md
+++ b/README.md
@@ -6,223 +6,77 @@
[](https://opensource.byjg.com/opensource/licensing.html)
[](https://github.com/byjg/php-mailwrapper/releases/)
-A lightweight wrapper for send mail. The interface is tottaly decoupled from the sender. The motivation is
-create a single interface for sending mail doesn't matter the sender. There are three options available:
+A lightweight wrapper for sending email. The interface is totally decoupled from the sender, providing a single interface for sending mail regardless of the underlying mail service.
-- SMTP (with SSL/TLS)
-- AWS SES (using API directly)
-- Mailgun (using API directly)
+## Available Wrappers
-## How to use
+- **SMTP** - SMTP with SSL/TLS support
+- **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)
-The MailWrapper has your classes totally decoupled in three parts:
+## Install
+
+```shell
+composer require "byjg/mailwrapper"
+```
-- The Envelope: the mail envelope. Defines the mail sender, recipients, body, subject, etc;
-- The Mailer: the responsible to deal with the process of send the envelope
-- The Register: Will register the available Mailers in the system.
+## Documentation
-### Envelope Class
+- **[Getting Started](docs/getting-started.md)** - Installation, quick start, and architecture overview
+- **[Envelope](docs/envelope.md)** - Creating and configuring email messages
+- **[Connection Strings](docs/connection-strings.md)** - URI patterns for different mail services (SMTP, Mailgun, SES, etc.)
+- **[Mailer Factory](docs/mailer-factory.md)** - Registering and creating mailers
+- **[Attachments](docs/attachments.md)** - Sending attachments and embedded images
+- **[Custom Wrappers](docs/custom-wrappers.md)** - Implementing your own mail wrapper
+- **[Exceptions](docs/exceptions.md)** - Error handling and exception types
-MailWrapper provides a envelope class with all the basic necessary attributes to create an email.
-As this Envelope class are totally decoupled from the Mailer engine, you can use it also as DTO.
-See an example below: (do not forget `require "vendor/autoload.php"`)
+## Quick Start
```php
setFrom('johndoe@example.com', 'John Doe');
$envelope->addTo('jane@example.com');
$envelope->setSubject('Email Subject');
-$envelope->setBody('html text body');
-```
-
-### Sending the email
+$envelope->setBody('
Hello World
');
-Once you have created the envelope you can send the email. Basically you have to register in the fabric all mailer
-you intend to use and then create the mailer:
-
-```php
-send($envelope);
-```
-
-You can create the mailer directly without the factory:
-
-```php
-send($envelope);
-```
-
-### Sending attachment
+// Create mailer from connection string
+$mailer = \ByJG\Mail\MailerFactory::create('smtp://username:password@smtp.example.com:587');
-```php
-addAttachment('name_of_attachement', '/path/to/file', 'mime/type');
-$mailer->send($envelope);
+// Send the email
+$result = $mailer->send($envelope);
```
-### Adding attachment as Embed Image
+## Architecture
-Adding an image as a inline attachment (or Embed) your mail reader will not show as download but you can
-use it as an local image in your email.
+MailWrapper is organized into three main components:
-See the example:
+- **The Envelope**: The mail message. Defines the sender, recipients, body, subject, attachments, etc.
+- **The Mailer**: Responsible for the process of sending the envelope
+- **The Factory**: Registers and creates the available Mailers in the system
-```php
-addEmbedImage('mycontentname', '/path/to/image', 'mime/type');
-$envelope->setBody('');
-$mailer->send($envelope);
-```
-
-## The connection url
-
-To create a new sender you have to define a URL like that:
-
-```text
-scheme://username:password/smtpserver:port
-```
-
-The options are:
-
-| Part | Description |
-|:-----------|:--------------------------------------------------------------------------------------------------------|
-| scheme | The email scheme: smtp, ssl, tls, mandrill and ses. Note that mandrill and ses use your own private api |
-| username | The username |
-| password | The password |
-| smtpserver | The SMTP Host |
-| port | The SMTP Port |
-
-The protocols available are:
-
-| Scheme | Description | URI Pattern | Mailer Object |
-|:-----------|:-----------------------------------|:-----------------------------------------|:-------------------|
-| smtp | SMTP over insecure connection | `smtp://username:password@host:25` | PHPMailerWrapper |
-| tls | SMTP over secure TLS connection | `tls://username:password@host:587` | PHPMailerWrapper |
-| ssl | SMTP over secure SSL connection | `ssl://username:password@host:587` | PHPMailerWrapper |
-| sendmail | Sending Email using PHP mail() | `sendmail://localhost` | SendMailWrapper |
-| mailgun | Sending Email using Mailgun API | `mailgun://YOUR_API_KEY@YOUR_DOMAIN` | MailgunApiWrapper |
-| ses | Sending Email using Amazon AWS API | `ses://ACCESS_KEY_ID:SECRET_KEY@REGION` | AmazonSesWrapper |
-| fakesender | Do nothing | `fakesender://anything` | FakeSenderWrapper |
-
-### Gmail specifics
-
-From December 2014, Google started imposing an authentication mechanism called
-XOAUTH2 based on OAuth2 for access to their apps, including Gmail.
-This change can break both SMTP and IMAP access to gmail, and you may receive
-authentication failures (often "5.7.14 Please log in via your web browser")
-from many email clients, including PHPMailer, Apple Mail, Outlook, Thunderbird and others.
-The error output may include a link to
-[https://support.google.com/mail/bin/answer.py?answer=78754](https://support.google.com/mail/bin/answer.py?answer=78754), which
-gives a list of possible remedies.
-
-There are two main solutions:
-
-#### Sending through SMTP
-
-You have to enable the option "Allow less secure apps".
-It does not really make your app significantly less secure.
-Reportedly, changing this setting may take an hour or more to take effect,
-so don't expect an immediate fix. You can start changing
-[here](https://www.google.com/settings/security/lesssecureapps)
-
-The connection string for sending emails using SMTP through GMAIL is:
-
-```text
-tls://YOUREMAIL@gmail.com:YOURPASSWORD@smtp.gmail.com:587
-```
+## Connection URL Schemes
-#### Sending Through XOAuth2
+| Scheme | Description | URI Pattern |
+|:-----------|:-----------------------------------|:-----------------------------------------|
+| smtp | SMTP over insecure connection | `smtp://username:password@host:25` |
+| tls | SMTP over secure TLS connection | `tls://username:password@host:587` |
+| ssl | SMTP over secure SSL connection | `ssl://username:password@host:465` |
+| sendmail | PHP's built-in mail() function | `sendmail://localhost` |
+| mailgun | Mailgun API | `mailgun://YOUR_API_KEY@YOUR_DOMAIN` |
+| ses | Amazon SES API | `ses://ACCESS_KEY_ID:SECRET_KEY@REGION` |
+| fakesender | Testing (does nothing) | `fakesender://localhost` |
-This option is currently unsupported.
-
-Further information and documentation on how to set up can be found on this
-[wiki](https://github.com/PHPMailer/PHPMailer/wiki/Using-Gmail-with-XOAUTH2) page.
-
-### Amazon SES API specifics
-
-The connection url for the AWS SES api is:
-
-```text
-ses://ACCESS_KEY_ID:SECRET_KEY@REGION
-```
-
-The access_key_id and secret_key are created at AWS Control Panel. The region can be us-east-1, etc.
-
-### Mailgun API specifics
-
-The connection url for the Mailgun api is:
-
-```text
-mailgun://YOUR_API_KEY@YOUR_DOMAIN
-```
-
-The YOUR_API_KEY and YOUR_DOMAIN are defined at Mailgun Control Panel.
-
-The Region of the endpoint can be configured by query parameter "region" (example: mailgun://api-key@mg.domain.cz?region=eu)
-
-Valid values are: us and eu.
-
-### Sendmail Specifics
-
-The connection url for the Sendmail is:
-
-```text
-sendmail://localhost
-```
-
-You need to setup in the `php.ini` the email relay.
-
-## Implementing your Own Wrappers
-
-To implement your own wrapper you have to create a class inherited from: `ByJG\Mail\Wrapper\BaseWrapper` and implement
-how to send in the method: `public function send(Envelope $envelope);`
-
-```php
-class MyWrapper extends \ByJG\Mail\Wrapper\BaseWrapper
-{
- public static function schema()
- {
- return ['mywrapper'];
- }
-
- public function send(Envelope $envelope): \ByJG\Mail\SendResult
- {
- // Do how to send the email using your library
- }
-
- // You can create your own validation methods.
- public function validate(Envelope $envelope)
- {
- parent::validate($envelope);
- }
-}
-```
-
-## Install
-
-```shell
-composer require "byjg/mailwrapper"
-```
+See [Connection Strings](docs/connection-strings.md) for detailed configuration examples.
## Running Tests
@@ -234,12 +88,9 @@ composer require "byjg/mailwrapper"
```mermaid
flowchart TD
- byjg/mailwrapper --> ext-curl
byjg/mailwrapper --> byjg/convert
byjg/mailwrapper --> byjg/webrequest
- byjg/mailwrapper --> aws/aws-sdk-php
- byjg/mailwrapper --> phpmailer/phpmailer
```
----
-[Open source ByJG](http://opensource.byjg.com)
\ No newline at end of file
+[Open source ByJG](http://opensource.byjg.com)
diff --git a/composer.json b/composer.json
index 6d8aa40..e1d5a08 100644
--- a/composer.json
+++ b/composer.json
@@ -14,16 +14,20 @@
"prefer-stable": true,
"minimum-stability": "dev",
"require": {
- "php": ">=8.1 <8.4",
+ "php": ">=8.1 <8.5",
"ext-curl": "*",
- "byjg/convert": "^5.0",
- "byjg/webrequest": "^5.0",
+ "byjg/convert": "^6.0",
+ "byjg/webrequest": "^6.0",
"aws/aws-sdk-php": "~3.20",
"phpmailer/phpmailer": ">=6.4.1"
},
"require-dev": {
- "phpunit/phpunit": "^9.6",
- "vimeo/psalm": "^5.9"
+ "phpunit/phpunit": "^10|^11",
+ "vimeo/psalm": "^5.9|^6.12"
+ },
+ "scripts": {
+ "test": "vendor/bin/phpunit",
+ "psalm": "vendor/bin/psalm"
},
"license": "MIT"
}
diff --git a/docs/attachments.md b/docs/attachments.md
new file mode 100644
index 0000000..0b506f4
--- /dev/null
+++ b/docs/attachments.md
@@ -0,0 +1,167 @@
+---
+sidebar_position: 5
+---
+
+# Attachments
+
+The Envelope class supports two types of attachments: regular attachments and embedded images.
+
+## Regular Attachments
+
+Regular attachments appear as downloadable files in the email client.
+
+### Adding Attachments
+
+```php
+$envelope = new \ByJG\Mail\Envelope('from@email.com', 'to@email.com', 'Subject', 'Body');
+
+$envelope->addAttachment(
+ 'filename.pdf', // Name shown in email
+ '/path/to/file.pdf', // Path to file on disk
+ 'application/pdf' // MIME type
+);
+
+// Add multiple attachments
+$envelope->addAttachment('document.docx', '/path/to/doc.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document');
+$envelope->addAttachment('image.png', '/path/to/image.png', 'image/png');
+
+$mailer->send($envelope);
+```
+
+### Common MIME Types
+
+| File Type | MIME Type |
+|:----------|:----------|
+| PDF | `application/pdf` |
+| Word (.docx) | `application/vnd.openxmlformats-officedocument.wordprocessingml.document` |
+| Excel (.xlsx) | `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` |
+| PNG | `image/png` |
+| JPEG | `image/jpeg` |
+| GIF | `image/gif` |
+| ZIP | `application/zip` |
+| Plain Text | `text/plain` |
+| CSV | `text/csv` |
+| JSON | `application/json` |
+
+## Embedded Images
+
+Embedded images (inline attachments) are displayed directly in the email body rather than as downloadable files. This is useful for including logos, diagrams, or other images in your HTML email.
+
+### Adding Embedded Images
+
+```php
+$envelope = new \ByJG\Mail\Envelope('from@email.com', 'to@email.com', 'Subject');
+
+// Add the image as an embedded attachment
+$envelope->addEmbedImage(
+ 'company_logo', // Content ID (used in HTML)
+ '/path/to/logo.png', // Path to image file
+ 'image/png' // MIME type
+);
+
+// Reference the image in HTML using cid: protocol
+$envelope->setBody('');
+
+$mailer->send($envelope);
+```
+
+### Multiple Embedded Images
+
+```php
+$envelope = new \ByJG\Mail\Envelope('from@email.com', 'to@email.com', 'Newsletter');
+
+// Add multiple images
+$envelope->addEmbedImage('header', '/path/to/header.png', 'image/png');
+$envelope->addEmbedImage('chart', '/path/to/chart.jpg', 'image/jpeg');
+$envelope->addEmbedImage('footer', '/path/to/footer.png', 'image/png');
+
+// Use all images in the HTML body
+$html = '
+
+
+
+
Check out our latest statistics:
+
+
+
+';
+
+$envelope->setBody($html);
+$mailer->send($envelope);
+```
+
+## Combining Both Types
+
+You can use both regular attachments and embedded images in the same email:
+
+```php
+$envelope = new \ByJG\Mail\Envelope('from@email.com', 'to@email.com', 'Report');
+
+// Embed logo in email body
+$envelope->addEmbedImage('logo', '/path/to/logo.png', 'image/png');
+
+// Attach PDF report for download
+$envelope->addAttachment('monthly_report.pdf', '/path/to/report.pdf', 'application/pdf');
+
+$html = '
+
+
+
+
Monthly Report
+
Please find the attached monthly report.
+
+';
+
+$envelope->setBody($html);
+$mailer->send($envelope);
+```
+
+## Getting Attachments
+
+You can retrieve all attachments from an envelope:
+
+```php
+$attachments = $envelope->getAttachments();
+
+// Returns an array like:
+// [
+// 'filename.pdf' => [
+// 'content' => '/path/to/file.pdf',
+// 'content-type' => 'application/pdf',
+// 'disposition' => 'attachment'
+// ],
+// 'logo' => [
+// 'content' => '/path/to/logo.png',
+// 'content-type' => 'image/png',
+// 'disposition' => 'inline'
+// ]
+// ]
+```
+
+The `disposition` field indicates whether it's a regular attachment (`attachment`) or an embedded image (`inline`).
+
+## Best Practices
+
+### File Paths
+
+- Use absolute paths to ensure files are found regardless of the current working directory
+- Verify files exist before adding them as attachments
+- Consider file size limits imposed by email servers (typically 25MB total)
+
+### Content IDs
+
+- Use descriptive content IDs for embedded images (e.g., `company_logo`, `header_image`)
+- Keep content IDs alphanumeric (avoid special characters)
+- Content IDs are case-sensitive
+
+### MIME Types
+
+- Always specify the correct MIME type for better compatibility
+- Use `image/png` for PNG files, `image/jpeg` for JPEG files
+- For unknown types, `application/octet-stream` is a safe fallback
+
+### Email Client Compatibility
+
+- Not all email clients handle embedded images the same way
+- Some clients may show embedded images as attachments in addition to displaying them inline
+- Always include `alt` attributes for images for accessibility
diff --git a/docs/connection-strings.md b/docs/connection-strings.md
new file mode 100644
index 0000000..e44502e
--- /dev/null
+++ b/docs/connection-strings.md
@@ -0,0 +1,109 @@
+---
+sidebar_position: 3
+---
+
+# Connection Strings
+
+Connection strings define how to connect to mail services. They follow a URI format:
+
+```text
+scheme://username:password@host:port
+```
+
+## URI Components
+
+| Part | Description |
+|:-----------|:-------------------------------------------------------------------------------|
+| scheme | The email scheme: smtp, ssl, tls, sendmail, mailgun, ses, fakesender |
+| username | The username for authentication |
+| password | The password for authentication |
+| host | The SMTP host or service endpoint |
+| port | The SMTP port |
+
+## Available Schemes
+
+| Scheme | Description | URI Pattern | Wrapper Class |
+|:-----------|:-----------------------------------|:-----------------------------------------|:-------------------|
+| smtp | SMTP over insecure connection | `smtp://username:password@host:25` | PHPMailerWrapper |
+| tls | SMTP over secure TLS connection | `tls://username:password@host:587` | PHPMailerWrapper |
+| ssl | SMTP over secure SSL connection | `ssl://username:password@host:465` | PHPMailerWrapper |
+| 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 |
+
+## Examples
+
+### SMTP with TLS
+
+```php
+$mailer = \ByJG\Mail\MailerFactory::create(
+ 'tls://username:password@smtp.example.com:587'
+);
+```
+
+### Gmail
+
+```php
+$mailer = \ByJG\Mail\MailerFactory::create(
+ 'tls://your.email@gmail.com:your_password@smtp.gmail.com:587'
+);
+```
+
+:::info
+Gmail requires you to enable "Allow less secure apps" in your Google account settings.
+Visit [https://www.google.com/settings/security/lesssecureapps](https://www.google.com/settings/security/lesssecureapps) to enable this option.
+
+Changes may take up to an hour to take effect.
+:::
+
+### Mailgun API
+
+```php
+$mailer = \ByJG\Mail\MailerFactory::create(
+ 'mailgun://YOUR_API_KEY@YOUR_DOMAIN'
+);
+```
+
+You can specify the region using a query parameter:
+
+```php
+// EU region
+$mailer = \ByJG\Mail\MailerFactory::create(
+ 'mailgun://YOUR_API_KEY@YOUR_DOMAIN?region=eu'
+);
+```
+
+Valid regions: `us` (default), `eu`
+
+### Amazon SES
+
+```php
+$mailer = \ByJG\Mail\MailerFactory::create(
+ 'ses://ACCESS_KEY_ID:SECRET_KEY@us-east-1'
+);
+```
+
+The region can be any valid AWS region (e.g., `us-east-1`, `eu-west-1`, etc.).
+
+### SendMail (PHP mail() function)
+
+```php
+$mailer = \ByJG\Mail\MailerFactory::create(
+ 'sendmail://localhost'
+);
+```
+
+:::warning
+You need to configure your email relay in `php.ini` for SendMail to work properly.
+:::
+
+### FakeSender (Testing)
+
+```php
+$mailer = \ByJG\Mail\MailerFactory::create(
+ 'fakesender://localhost'
+);
+```
+
+The FakeSender wrapper does nothing and always returns success. It's useful for testing without actually sending emails.
diff --git a/docs/custom-wrappers.md b/docs/custom-wrappers.md
new file mode 100644
index 0000000..23cc6b7
--- /dev/null
+++ b/docs/custom-wrappers.md
@@ -0,0 +1,290 @@
+---
+sidebar_position: 6
+---
+
+# Custom Wrappers
+
+You can implement your own mail wrapper to integrate with any email service or custom mail handling logic.
+
+## Creating a Custom Wrapper
+
+To create a custom wrapper, extend the `BaseWrapper` class and implement the required methods:
+
+```php
+uri
+ $apiKey = $this->uri->getUsername();
+ $apiSecret = $this->uri->getPassword();
+ $host = $this->uri->getHost();
+
+ // Validate the envelope
+ $this->validate($envelope);
+
+ // Your custom logic to send the email
+ $messageId = $this->sendViaMyService($envelope, $apiKey, $apiSecret, $host);
+
+ // Return the result
+ return new SendResult(true, $messageId);
+ }
+
+ private function sendViaMyService(Envelope $envelope, string $apiKey, string $apiSecret, string $host): string
+ {
+ // Implement your email sending logic here
+ // This might involve:
+ // - Making API calls
+ // - Formatting the email data
+ // - Handling attachments
+ // - Error handling
+
+ return 'message-id-123';
+ }
+}
+```
+
+## Implementing the Schema Method
+
+The `schema()` method defines which URI schemes your wrapper handles. Return an array of scheme names:
+
+```php
+public static function schema(): array
+{
+ return ['myservice']; // Handles myservice://...
+}
+```
+
+You can support multiple schemes:
+
+```php
+public static function schema(): array
+{
+ return ['myservice', 'myservice-ssl', 'myservice-tls'];
+}
+```
+
+## Implementing the Send Method
+
+The `send()` method must:
+
+1. Accept an `Envelope` parameter
+2. Return a `SendResult` object
+3. Handle the actual email delivery
+
+```php
+public function send(Envelope $envelope): SendResult
+{
+ // Validate the envelope (optional but recommended)
+ $this->validate($envelope);
+
+ try {
+ // Your sending logic
+ $messageId = $this->performSend($envelope);
+
+ // Return success
+ return new SendResult(true, $messageId);
+
+ } catch (\Exception $e) {
+ // Handle errors - you might throw an exception or return failure
+ throw new \ByJG\Mail\Exception\MailApiException(
+ 'Failed to send email: ' . $e->getMessage()
+ );
+ }
+}
+```
+
+## Accessing Connection Details
+
+The URI is available via `$this->uri`:
+
+```php
+// Get URI components
+$scheme = $this->uri->getScheme(); // e.g., 'myservice'
+$username = $this->uri->getUsername(); // e.g., 'api-key'
+$password = $this->uri->getPassword(); // e.g., 'secret'
+$host = $this->uri->getHost(); // e.g., 'api.myservice.com'
+$port = $this->uri->getPort(); // e.g., 443
+$query = $this->uri->getQuery(); // e.g., 'region=us'
+
+// Get query parameters
+$region = $this->uri->getQueryPart('region'); // Extract specific parameter
+```
+
+## Custom Validation
+
+You can add custom validation by overriding the `validate()` method:
+
+```php
+public function validate(Envelope $envelope): void
+{
+ // Call parent validation
+ parent::validate($envelope);
+
+ // Add your custom validation
+ if (empty($envelope->getSubject())) {
+ throw new \ByJG\Mail\Exception\InvalidMessageFormatException(
+ 'Subject is required'
+ );
+ }
+
+ if (!$envelope->isHtml() && !empty($envelope->getAttachments())) {
+ throw new \ByJG\Mail\Exception\InvalidMessageFormatException(
+ 'Attachments require HTML mode'
+ );
+ }
+}
+```
+
+The base `validate()` method checks:
+- At least one recipient exists
+- From address is set
+
+## Handling Attachments
+
+Process attachments from the envelope:
+
+```php
+private function processAttachments(Envelope $envelope): array
+{
+ $processed = [];
+
+ foreach ($envelope->getAttachments() as $name => $attachment) {
+ $filePath = $attachment['content'];
+ $mimeType = $attachment['content-type'];
+ $disposition = $attachment['disposition']; // 'attachment' or 'inline'
+
+ // Read file content
+ $content = file_get_contents($filePath);
+ $encoded = base64_encode($content);
+
+ $processed[] = [
+ 'name' => $name,
+ 'type' => $mimeType,
+ 'content' => $encoded,
+ 'disposition' => $disposition,
+ ];
+ }
+
+ return $processed;
+}
+```
+
+## Registering Your Wrapper
+
+Register your custom wrapper with the factory:
+
+```php
+\ByJG\Mail\MailerFactory::registerMailer(\MyApp\Mail\MyCustomWrapper::class);
+
+// Now you can use it
+$mailer = \ByJG\Mail\MailerFactory::create('myservice://api-key:secret@api.example.com');
+```
+
+## Complete Example
+
+Here's a complete example implementing a simple HTTP API wrapper:
+
+```php
+validate($envelope);
+
+ $apiUrl = sprintf(
+ 'https://%s/send',
+ $this->uri->getHost()
+ );
+
+ $payload = [
+ 'from' => $envelope->getFrom(),
+ 'to' => $envelope->getTo(),
+ 'subject' => $envelope->getSubject(),
+ 'html' => $envelope->getBody(),
+ 'api_key' => $this->uri->getUsername(),
+ ];
+
+ if (!empty($envelope->getCC())) {
+ $payload['cc'] = $envelope->getCC();
+ }
+
+ if (!empty($envelope->getBCC())) {
+ $payload['bcc'] = $envelope->getBCC();
+ }
+
+ $ch = curl_init($apiUrl);
+ curl_setopt($ch, CURLOPT_POST, true);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, [
+ 'Content-Type: application/json',
+ ]);
+
+ $response = curl_exec($ch);
+ $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ curl_close($ch);
+
+ if ($httpCode !== 200) {
+ throw new MailApiException(
+ sprintf('API returned error: %d - %s', $httpCode, $response)
+ );
+ }
+
+ $data = json_decode($response, true);
+
+ return new SendResult(true, $data['message_id'] ?? null);
+ }
+}
+```
+
+Usage:
+
+```php
+\ByJG\Mail\MailerFactory::registerMailer(\MyApp\Mail\HttpApiWrapper::class);
+
+$mailer = \ByJG\Mail\MailerFactory::create('httpapi://YOUR_API_KEY@api.emailservice.com');
+$mailer->send($envelope);
+```
+
+## Best Practices
+
+1. **Error Handling**: Always handle errors gracefully and throw appropriate exceptions
+2. **Validation**: Call `parent::validate()` before your custom validation
+3. **Return Values**: Always return a `SendResult` object with appropriate success status
+4. **Message IDs**: Include message IDs when available for tracking
+5. **Testing**: Create unit tests for your wrapper using the FakeSender as a reference
+6. **Documentation**: Document your wrapper's connection string format and requirements
diff --git a/docs/envelope.md b/docs/envelope.md
new file mode 100644
index 0000000..62c6e3f
--- /dev/null
+++ b/docs/envelope.md
@@ -0,0 +1,112 @@
+---
+sidebar_position: 2
+---
+
+# Envelope
+
+The Envelope class represents an email message. It's totally decoupled from the Mailer engine, so you can also use it as a DTO (Data Transfer Object).
+
+## Creating an Envelope
+
+### Basic Constructor
+
+```php
+$envelope = new \ByJG\Mail\Envelope();
+```
+
+### Constructor with Parameters
+
+```php
+$envelope = new \ByJG\Mail\Envelope(
+ 'from@example.com', // From address
+ 'to@example.com', // To address
+ 'Email Subject', // Subject
+ '
HTML Body
', // Body
+ true // isHtml (default: true)
+);
+```
+
+## Setting Email Properties
+
+### From Address
+
+```php
+// Simple from address
+$envelope->setFrom('johndoe@example.com');
+
+// From address with name
+$envelope->setFrom('johndoe@example.com', 'John Doe');
+```
+
+### Recipients
+
+```php
+// Set a single recipient (replaces existing)
+$envelope->setTo('jane@example.com', 'Jane Doe');
+
+// Add multiple recipients
+$envelope->addTo('user1@example.com');
+$envelope->addTo('user2@example.com', 'User Two');
+```
+
+### CC and BCC
+
+```php
+// Carbon Copy
+$envelope->addCC('manager@example.com', 'Manager');
+$envelope->setCC('manager@example.com'); // Replaces all CC
+
+// Blind Carbon Copy
+$envelope->addBCC('admin@example.com');
+$envelope->setBCC('admin@example.com'); // Replaces all BCC
+```
+
+### Subject and Body
+
+```php
+// Set subject
+$envelope->setSubject('Important Notice');
+
+// Set HTML body
+$envelope->setBody('
Hello
This is an HTML email
');
+$envelope->isHtml(true);
+
+// Set plain text body
+$envelope->setBody('This is plain text');
+$envelope->isHtml(false);
+```
+
+### Reply-To
+
+```php
+$envelope->setReplyTo('support@example.com');
+
+// If not set, defaults to the From address
+$replyTo = $envelope->getReplyTo();
+```
+
+## Getting Properties
+
+All properties have corresponding getter methods:
+
+```php
+$from = $envelope->getFrom();
+$to = $envelope->getTo(); // Returns array
+$subject = $envelope->getSubject();
+$body = $envelope->getBody();
+$cc = $envelope->getCC(); // Returns array
+$bcc = $envelope->getBCC(); // Returns array
+$isHtml = $envelope->isHtml();
+```
+
+## Text Body Generation
+
+The Envelope can automatically generate a plain text version of an HTML body:
+
+```php
+$envelope->setBody('
Title
Paragraph
');
+$textBody = $envelope->getBodyText();
+// Returns: "# Title\n\nParagraph\n"
+```
+
+This is useful for multipart emails that include both HTML and plain text versions.
diff --git a/docs/exceptions.md b/docs/exceptions.md
new file mode 100644
index 0000000..12fcdb4
--- /dev/null
+++ b/docs/exceptions.md
@@ -0,0 +1,282 @@
+---
+sidebar_position: 7
+---
+
+# Exceptions
+
+MailWrapper defines several exception classes to handle different error conditions. All exceptions are in the `ByJG\Mail\Exception` namespace.
+
+## Exception Hierarchy
+
+All MailWrapper exceptions extend standard PHP exceptions, allowing you to catch them individually or as a group.
+
+```text
+\Exception
+├── InvalidEMailException
+├── InvalidMailHandlerException
+├── InvalidMessageFormatException
+├── MailApiException
+└── ProtocolNotRegisteredException
+```
+
+## Exception Types
+
+### InvalidEMailException
+
+Thrown when email validation fails.
+
+**Common causes:**
+- Missing sender address
+- Missing recipient address
+- Invalid email format
+
+**Example:**
+
+```php
+use ByJG\Mail\Exception\InvalidEMailException;
+
+try {
+ $envelope = new \ByJG\Mail\Envelope();
+ // No from or to addresses set
+ $mailer->send($envelope);
+} catch (InvalidEMailException $e) {
+ echo "Email validation failed: " . $e->getMessage();
+ // Output: "Destination Email was not provided"
+}
+```
+
+### ProtocolNotRegisteredException
+
+Thrown when trying to create a mailer for an unregistered protocol scheme.
+
+**Common causes:**
+- Forgetting to register a wrapper with `MailerFactory::registerMailer()`
+- Using an invalid or misspelled scheme in the connection string
+- Wrapper not installed or available
+
+**Example:**
+
+```php
+use ByJG\Mail\Exception\ProtocolNotRegisteredException;
+
+try {
+ // Forgot to register the SMTP wrapper
+ $mailer = \ByJG\Mail\MailerFactory::create('smtp://user:pass@host');
+} catch (ProtocolNotRegisteredException $e) {
+ echo "Protocol error: " . $e->getMessage();
+ // Output: "Protocol not found/registered!"
+}
+```
+
+**Solution:**
+
+```php
+// Register the wrapper before creating the mailer
+\ByJG\Mail\MailerFactory::registerMailer(\ByJG\Mail\Wrapper\PHPMailerWrapper::class);
+$mailer = \ByJG\Mail\MailerFactory::create('smtp://user:pass@host');
+```
+
+### InvalidMailHandlerException
+
+Thrown when trying to register an invalid wrapper class.
+
+**Common causes:**
+- Registering a class that doesn't implement `MailWrapperInterface`
+- Passing a non-existent class name
+
+**Example:**
+
+```php
+use ByJG\Mail\Exception\InvalidMailHandlerException;
+
+try {
+ \ByJG\Mail\MailerFactory::registerMailer(\MyApp\InvalidClass::class);
+} catch (InvalidMailHandlerException $e) {
+ echo "Registration error: " . $e->getMessage();
+ // Output: "Class not implements ConnectorInterface!"
+}
+```
+
+### InvalidMessageFormatException
+
+Thrown when the message format is invalid or incomplete.
+
+**Common causes:**
+- Invalid message structure
+- Missing required fields
+- Malformed content
+
+**Example:**
+
+```php
+use ByJG\Mail\Exception\InvalidMessageFormatException;
+
+// This exception might be thrown by custom wrappers with additional validation
+try {
+ // Some wrapper that validates subject is not empty
+ $mailer->send($envelope);
+} catch (InvalidMessageFormatException $e) {
+ echo "Message format error: " . $e->getMessage();
+}
+```
+
+### MailApiException
+
+Thrown when an email API returns an error.
+
+**Common causes:**
+- Invalid API credentials
+- API rate limiting
+- Network connectivity issues
+- Service outages
+- Invalid email addresses rejected by the API
+
+**Example:**
+
+```php
+use ByJG\Mail\Exception\MailApiException;
+
+try {
+ $mailer = \ByJG\Mail\MailerFactory::create('mailgun://invalid_key@domain.com');
+ $mailer->send($envelope);
+} catch (MailApiException $e) {
+ echo "API error: " . $e->getMessage();
+ // Might include API-specific error details
+}
+```
+
+## Exception Handling Best Practices
+
+### Catch Specific Exceptions
+
+Handle different exception types appropriately:
+
+```php
+use ByJG\Mail\Exception\{
+ InvalidEMailException,
+ ProtocolNotRegisteredException,
+ MailApiException
+};
+
+try {
+ $mailer = \ByJG\Mail\MailerFactory::create($connection);
+ $result = $mailer->send($envelope);
+
+} catch (InvalidEMailException $e) {
+ // Validation error - fix the envelope data
+ error_log("Invalid email configuration: " . $e->getMessage());
+
+} catch (ProtocolNotRegisteredException $e) {
+ // Configuration error - register the protocol
+ error_log("Missing protocol registration: " . $e->getMessage());
+
+} catch (MailApiException $e) {
+ // API error - might be temporary, consider retrying
+ error_log("Mail service API error: " . $e->getMessage());
+
+} catch (\Exception $e) {
+ // Catch-all for unexpected errors
+ error_log("Unexpected error: " . $e->getMessage());
+}
+```
+
+### Validate Before Sending
+
+Validate the envelope before attempting to send:
+
+```php
+$envelope = new \ByJG\Mail\Envelope();
+
+// Validate manually if needed
+if (empty($envelope->getFrom())) {
+ throw new \ByJG\Mail\Exception\InvalidEMailException('From address required');
+}
+
+if (count($envelope->getTo()) === 0) {
+ throw new \ByJG\Mail\Exception\InvalidEMailException('At least one recipient required');
+}
+```
+
+### Logging and Debugging
+
+Include context in error handling:
+
+```php
+try {
+ $result = $mailer->send($envelope);
+
+ if (!$result->success) {
+ error_log(sprintf(
+ 'Failed to send email to %s: %s',
+ implode(', ', $envelope->getTo()),
+ 'Unknown error'
+ ));
+ }
+
+} catch (\Exception $e) {
+ error_log(sprintf(
+ 'Exception sending email to %s: %s - %s',
+ implode(', ', $envelope->getTo()),
+ get_class($e),
+ $e->getMessage()
+ ));
+
+ // Optionally include stack trace in development
+ if (DEBUG_MODE) {
+ error_log($e->getTraceAsString());
+ }
+}
+```
+
+### Retry Logic
+
+Implement retry logic for transient failures:
+
+```php
+use ByJG\Mail\Exception\MailApiException;
+
+function sendWithRetry($mailer, $envelope, $maxAttempts = 3): bool
+{
+ $attempt = 0;
+
+ while ($attempt < $maxAttempts) {
+ try {
+ $result = $mailer->send($envelope);
+ return $result->success;
+
+ } catch (MailApiException $e) {
+ $attempt++;
+
+ if ($attempt >= $maxAttempts) {
+ throw $e;
+ }
+
+ // Exponential backoff
+ sleep(pow(2, $attempt));
+ }
+ }
+
+ return false;
+}
+```
+
+### Graceful Degradation
+
+Consider fallback mechanisms:
+
+```php
+$primaryMailer = \ByJG\Mail\MailerFactory::create('mailgun://key@domain');
+$fallbackMailer = \ByJG\Mail\MailerFactory::create('smtp://user:pass@host:587');
+
+try {
+ $result = $primaryMailer->send($envelope);
+} catch (\Exception $e) {
+ error_log('Primary mailer failed, using fallback: ' . $e->getMessage());
+ try {
+ $result = $fallbackMailer->send($envelope);
+ } catch (\Exception $e2) {
+ error_log('Fallback mailer also failed: ' . $e2->getMessage());
+ throw $e2;
+ }
+}
+```
diff --git a/docs/getting-started.md b/docs/getting-started.md
new file mode 100644
index 0000000..df93620
--- /dev/null
+++ b/docs/getting-started.md
@@ -0,0 +1,65 @@
+---
+sidebar_position: 1
+---
+
+# Getting Started
+
+A lightweight wrapper for sending email. The interface is totally decoupled from the sender, providing a single interface for sending mail regardless of the underlying mail service.
+
+## Installation
+
+```shell
+composer require "byjg/mailwrapper"
+```
+
+## Quick Start
+
+Here's a simple example to get you started:
+
+```php
+setFrom('johndoe@example.com', 'John Doe');
+$envelope->addTo('jane@example.com');
+$envelope->setSubject('Email Subject');
+$envelope->setBody('
Hello World
This is an HTML email
');
+
+// Register the available mailers
+\ByJG\Mail\MailerFactory::registerMailer(\ByJG\Mail\Wrapper\PHPMailerWrapper::class);
+\ByJG\Mail\MailerFactory::registerMailer(\ByJG\Mail\Wrapper\MailgunApiWrapper::class);
+
+// Create the mailer based on the connection string
+$mailer = \ByJG\Mail\MailerFactory::create('smtp://username:password@smtp.example.com:587');
+
+// Send the email
+$result = $mailer->send($envelope);
+
+if ($result->success) {
+ echo "Email sent successfully! ID: " . $result->id;
+}
+```
+
+## Architecture
+
+MailWrapper is organized into three main components:
+
+- **The Envelope**: The mail envelope. Defines the mail sender, recipients, body, subject, etc.
+- **The Mailer**: Responsible for the process of sending the envelope
+- **The Factory**: Registers and creates the available Mailers in the system
+
+## Available Wrappers
+
+- **SMTP** - Standard SMTP with SSL/TLS support
+- **AWS SES** - Amazon Simple Email Service (using API directly)
+- **Mailgun** - Mailgun API
+- **SendMail** - PHP's built-in mail() function
+- **FakeSender** - For testing (does nothing)
+
+## Running Tests
+
+```shell
+./vendor/bin/phpunit
+```
diff --git a/docs/mailer-factory.md b/docs/mailer-factory.md
new file mode 100644
index 0000000..0042354
--- /dev/null
+++ b/docs/mailer-factory.md
@@ -0,0 +1,162 @@
+---
+sidebar_position: 4
+---
+
+# Mailer Factory
+
+The MailerFactory is responsible for creating mailer instances based on connection strings. It uses a registration pattern that allows you to register which mailer wrappers are available in your application.
+
+## Registering Mailers
+
+Before creating a mailer, you need to register the wrapper classes you want to use:
+
+```php
+// Register individual wrappers
+\ByJG\Mail\MailerFactory::registerMailer(\ByJG\Mail\Wrapper\PHPMailerWrapper::class);
+\ByJG\Mail\MailerFactory::registerMailer(\ByJG\Mail\Wrapper\MailgunApiWrapper::class);
+\ByJG\Mail\MailerFactory::registerMailer(\ByJG\Mail\Wrapper\AmazonSesWrapper::class);
+```
+
+You only need to register the wrappers you plan to use. This keeps your application lightweight by not loading unnecessary dependencies.
+
+## Creating Mailers
+
+Once registered, create a mailer using a connection string:
+
+```php
+$mailer = \ByJG\Mail\MailerFactory::create('smtp://username:password@host:587');
+```
+
+The factory automatically selects the appropriate wrapper based on the connection string's scheme.
+
+### Using URI Objects
+
+You can also pass a URI object instead of a string:
+
+```php
+$uri = new \ByJG\Util\Uri('tls://username:password@smtp.example.com:587');
+$mailer = \ByJG\Mail\MailerFactory::create($uri);
+```
+
+## Creating Mailers Directly
+
+You can bypass the factory and instantiate wrappers directly:
+
+```php
+$mailer = new \ByJG\Mail\Wrapper\MailgunApiWrapper(
+ new \ByJG\Util\Uri('mailgun://YOUR_API_KEY@YOUR_DOMAIN')
+);
+```
+
+This approach is useful when:
+- You only use a single mailer type
+- You want to avoid the registration step
+- You need more control over instantiation
+
+## Sending Emails
+
+All mailers implement the same interface:
+
+```php
+$envelope = new \ByJG\Mail\Envelope(
+ 'from@example.com',
+ 'to@example.com',
+ 'Subject',
+ 'Body content'
+);
+
+$result = $mailer->send($envelope);
+
+if ($result->success) {
+ echo "Email sent! Message ID: " . $result->id;
+} else {
+ echo "Failed to send email";
+}
+```
+
+## Send Result
+
+The `send()` method returns a `SendResult` object with two properties:
+
+```php
+class SendResult
+{
+ public readonly bool $success; // true if email was sent
+ public readonly ?string $id; // Message ID (if available)
+}
+```
+
+Example:
+
+```php
+$result = $mailer->send($envelope);
+
+if ($result->success) {
+ // Email was sent successfully
+ if ($result->id !== null) {
+ // Some services provide a message ID for tracking
+ log("Email sent with ID: " . $result->id);
+ }
+}
+```
+
+## Exception Handling
+
+The factory may throw exceptions:
+
+```php
+use ByJG\Mail\Exception\ProtocolNotRegisteredException;
+use ByJG\Mail\Exception\InvalidMailHandlerException;
+
+try {
+ $mailer = \ByJG\Mail\MailerFactory::create('unknown://host');
+} catch (ProtocolNotRegisteredException $e) {
+ // The scheme 'unknown' hasn't been registered
+ echo "Protocol not registered: " . $e->getMessage();
+}
+```
+
+## Best Practices
+
+### Configuration Management
+
+Store connection strings in configuration files or environment variables:
+
+```php
+// .env file
+MAIL_CONNECTION=tls://user:pass@smtp.example.com:587
+
+// In your application
+$mailer = \ByJG\Mail\MailerFactory::create($_ENV['MAIL_CONNECTION']);
+```
+
+### Single Registration Point
+
+Register all mailers once during application bootstrap:
+
+```php
+// bootstrap.php
+$wrappers = [
+ \ByJG\Mail\Wrapper\PHPMailerWrapper::class,
+ \ByJG\Mail\Wrapper\MailgunApiWrapper::class,
+ \ByJG\Mail\Wrapper\AmazonSesWrapper::class,
+ \ByJG\Mail\Wrapper\SendMailWrapper::class,
+];
+
+foreach ($wrappers as $wrapper) {
+ \ByJG\Mail\MailerFactory::registerMailer($wrapper);
+}
+```
+
+### Testing
+
+Use FakeSender for testing:
+
+```php
+// Test configuration
+if ($isTestEnvironment) {
+ $mailer = \ByJG\Mail\MailerFactory::create('fakesender://localhost');
+} else {
+ $mailer = \ByJG\Mail\MailerFactory::create($productionConnection);
+}
+```
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index d5df793..c090a6d 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -6,14 +6,21 @@ and open the template in the editor.
-->
-
+ displayDetailsOnTestsThatTriggerDeprecations="true"
+ displayDetailsOnTestsThatTriggerErrors="true"
+ displayDetailsOnTestsThatTriggerNotices="true"
+ displayDetailsOnTestsThatTriggerWarnings="true"
+ displayDetailsOnPhpunitDeprecations="true"
+ failOnWarning="true"
+ failOnNotice="true"
+ failOnDeprecation="true"
+ failOnPhpunitDeprecation="true"
+ stopOnFailure="false"
+ xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd">
@@ -21,16 +28,15 @@ and open the template in the editor.
-
-
- ./src
-
-
+
+
+ ./src/
+
+ ./tests/
-
-
+
\ No newline at end of file
diff --git a/psalm.xml b/psalm.xml
index ebabb1a..b208114 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -4,6 +4,7 @@
resolveFromConfigFile="true"
findUnusedBaselineEntry="true"
findUnusedCode="false"
+ cacheDirectory="/tmp/psalm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
diff --git a/src/MailerFactory.php b/src/MailerFactory.php
index 9d2200b..ab7cb93 100644
--- a/src/MailerFactory.php
+++ b/src/MailerFactory.php
@@ -11,6 +11,7 @@
use ByJG\Mail\Exception\ProtocolNotRegisteredException;
use ByJG\Mail\Wrapper\MailWrapperInterface;
use ByJG\Util\Uri;
+use Psr\Http\Message\UriInterface;
class MailerFactory
{
@@ -18,9 +19,12 @@ class MailerFactory
/**
* @param string $class
+ *
* @throws InvalidMailHandlerException
+ *
+ * @return void
*/
- public static function registerMailer(string $class)
+ public static function registerMailer(string $class): void
{
if (!in_array(MailWrapperInterface::class, class_implements($class))) {
throw new InvalidMailHandlerException('Class not implements ConnectorInterface!');
@@ -35,13 +39,16 @@ public static function registerMailer(string $class)
/**
- * @param string $connection
+ * @param Uri|string $connection
* @return MailWrapperInterface
* @throws ProtocolNotRegisteredException
*/
- public static function create(string $connection): MailWrapperInterface
+ public static function create(UriInterface|string $connection): MailWrapperInterface
{
- $uri = new Uri($connection);
+ $uri = $connection;
+ if (is_string($connection)) {
+ $uri = new Uri($connection);
+ }
if (!isset(self::$config[$uri->getScheme()])) {
throw new ProtocolNotRegisteredException('Protocol not found/registered!');
diff --git a/src/Wrapper/AmazonSesWrapper.php b/src/Wrapper/AmazonSesWrapper.php
index ac27bac..28d8650 100644
--- a/src/Wrapper/AmazonSesWrapper.php
+++ b/src/Wrapper/AmazonSesWrapper.php
@@ -13,15 +13,16 @@
class AmazonSesWrapper extends PHPMailerWrapper
{
+ #[\Override]
public static function schema(): array
{
return ['ses'];
}
/**
- * @return mixed
+ * @return SesClient
*/
- public function getSesClient(): mixed
+ public function getSesClient(): SesClient
{
//Send the message (which must be base 64 encoded):
return new SesClient([
@@ -43,6 +44,7 @@ public function getSesClient(): mixed
* @throws InvalidEMailException
* @throws InvalidMessageFormatException
*/
+ #[\Override]
public function send(Envelope $envelope): SendResult
{
$this->validate($envelope);
diff --git a/src/Wrapper/FakeSenderWrapper.php b/src/Wrapper/FakeSenderWrapper.php
index f634dc5..a87bc0d 100644
--- a/src/Wrapper/FakeSenderWrapper.php
+++ b/src/Wrapper/FakeSenderWrapper.php
@@ -7,11 +7,13 @@
class FakeSenderWrapper extends BaseWrapper
{
+ #[\Override]
public static function schema(): array
{
return ['fake', 'fakesender'];
}
+ #[\Override]
public function send(Envelope $envelope): SendResult
{
return new SendResult(true, 'fake-id-123');
diff --git a/src/Wrapper/MailgunApiWrapper.php b/src/Wrapper/MailgunApiWrapper.php
index cdea6f2..2dc4c47 100644
--- a/src/Wrapper/MailgunApiWrapper.php
+++ b/src/Wrapper/MailgunApiWrapper.php
@@ -27,12 +27,13 @@ class MailgunApiWrapper extends PHPMailerWrapper
'eu' => 'api.eu.mailgun.net',
];
+ #[\Override]
public static function schema(): array
{
return ['mailgun'];
}
- public function __construct(Uri $uri, ClientInterface $client = null)
+ public function __construct(Uri $uri, ?ClientInterface $client = null)
{
parent::__construct($uri);
@@ -53,7 +54,7 @@ public function getRequestObject(): RequestInterface
$domainName = $this->uri->getHost();
$apiUri = $this->getApiUri();
- $uri = Uri::getInstanceFromString("https://$apiUri/v3/$domainName/messages")
+ $uri = Uri::getInstance("https://$apiUri/v3/$domainName/messages")
->withUserInfo('api', $this->uri->getUsername());
return Request::getInstance($uri)->withMethod("POST");
@@ -71,6 +72,7 @@ public function getRequestObject(): RequestInterface
* @throws NetworkException
* @throws RequestException
*/
+ #[\Override]
public function send(Envelope $envelope): SendResult
{
$this->validate($envelope);
diff --git a/src/Wrapper/PHPMailerWrapper.php b/src/Wrapper/PHPMailerWrapper.php
index 43072f1..55f7ed3 100644
--- a/src/Wrapper/PHPMailerWrapper.php
+++ b/src/Wrapper/PHPMailerWrapper.php
@@ -13,6 +13,7 @@
class PHPMailerWrapper extends BaseWrapper
{
+ #[\Override]
public static function schema(): array
{
return ['smtp', 'tls', 'ssl'];
@@ -106,6 +107,7 @@ protected function prepareMailer(Envelope $envelope): PHPMailerOverride
* @throws InvalidEMailException
* @throws MailApiException
*/
+ #[\Override]
public function send(Envelope $envelope): SendResult
{
$this->validate($envelope);
diff --git a/src/Wrapper/SendMailWrapper.php b/src/Wrapper/SendMailWrapper.php
index ac75ede..0d82150 100644
--- a/src/Wrapper/SendMailWrapper.php
+++ b/src/Wrapper/SendMailWrapper.php
@@ -18,6 +18,7 @@
class SendMailWrapper extends PHPMailerWrapper
{
+ #[\Override]
public static function schema(): array
{
return ['sendmail'];
@@ -30,6 +31,7 @@ public static function schema(): array
* @throws InvalidEMailException
* @throws InvalidMessageFormatException
*/
+ #[\Override]
public function send(Envelope $envelope): SendResult
{
$this->validate($envelope);
diff --git a/tests/AmazonSesWrapperTest.php b/tests/AmazonSesTestWrapper.php
similarity index 88%
rename from tests/AmazonSesWrapperTest.php
rename to tests/AmazonSesTestWrapper.php
index e449c61..2217462 100644
--- a/tests/AmazonSesWrapperTest.php
+++ b/tests/AmazonSesTestWrapper.php
@@ -3,6 +3,7 @@
namespace Tests;
use Aws\Credentials\Credentials;
+use ByJG\Mail\Envelope;
use ByJG\Mail\Exception\InvalidEMailException;
use ByJG\Mail\Exception\InvalidMessageFormatException;
use ByJG\Mail\SendResult;
@@ -10,7 +11,7 @@
use ByJG\Util\Uri;
use PHPMailer\PHPMailer\Exception;
-class AmazonSesWrapperTest extends BaseWrapperTest
+class AmazonSesTestWrapper extends BaseTestWrapper
{
/**
* @param $envelope
@@ -19,7 +20,7 @@ class AmazonSesWrapperTest extends BaseWrapperTest
* @throws InvalidMessageFormatException
* @throws Exception
*/
- public function doMockedRequest($envelope): array
+ public function doMockedRequest(Envelope $envelope): array
{
$object = $this->getMockBuilder(AmazonSesWrapper::class)
->onlyMethods(['getSesClient'])
@@ -29,14 +30,14 @@ public function doMockedRequest($envelope): array
$mock = new MockSender();
$object->expects($this->once())
->method('getSesClient')
- ->will($this->returnValue($mock));
+ ->willReturn($mock);
$result = $object->send($envelope);
return [$mock, $result];
}
- public function testGetSesClient()
+ public function testGetSesClient(): void
{
$sesWrapper = new AmazonSesWrapper(new Uri('ses://ACCESS_KEY_ID:SECRET_KEY@REGION'));
$sesClient = $sesWrapper->getSesClient();
@@ -58,7 +59,7 @@ public function testGetSesClient()
* @throws InvalidMessageFormatException
* @throws InvalidEMailException
*/
- protected function send($envelope, $rawEmail): SendResult
+ protected function send(Envelope $envelope, string $rawEmail): SendResult
{
[$mock, $result] = $this->doMockedRequest($envelope);
$mimeMessage = $this->fixVariableFields(file_get_contents(__DIR__ . '/resources/' . $rawEmail . '.eml'));
@@ -80,7 +81,7 @@ protected function send($envelope, $rawEmail): SendResult
* @throws InvalidMessageFormatException
* @throws InvalidEMailException
*/
- public function testBasicEnvelope()
+ public function testBasicEnvelope(): void
{
$envelope = $this->getBasicEnvelope();
$result = $this->send($envelope, 'basicenvelope');
@@ -94,7 +95,7 @@ public function testBasicEnvelope()
* @throws InvalidMessageFormatException
* @throws InvalidEMailException
*/
- public function testFullEnvelope()
+ public function testFullEnvelope(): void
{
$envelope = $this->getFullEnvelope();
$result = $this->send($envelope, 'fullenvelope');
@@ -108,7 +109,7 @@ public function testFullEnvelope()
* @throws InvalidMessageFormatException
* @throws InvalidEMailException
*/
- public function testAttachmentEnvelope()
+ public function testAttachmentEnvelope(): void
{
$envelope = $this->getAttachmentEnvelope();
$result = $this->send($envelope, 'attachmentenvelope');
@@ -122,7 +123,7 @@ public function testAttachmentEnvelope()
* @throws InvalidMessageFormatException
* @throws InvalidEMailException
*/
- public function testEmbedImageEnvelope()
+ public function testEmbedImageEnvelope(): void
{
$envelope = $this->getEmbedImageEnvelope();
$result = $this->send($envelope, 'embedenvelope');
diff --git a/tests/BaseWrapperTest.php b/tests/BaseTestWrapper.php
similarity index 78%
rename from tests/BaseWrapperTest.php
rename to tests/BaseTestWrapper.php
index 80c187c..cac6e23 100644
--- a/tests/BaseWrapperTest.php
+++ b/tests/BaseTestWrapper.php
@@ -6,12 +6,12 @@
use ByJG\Mail\Util;
use PHPUnit\Framework\TestCase;
-abstract class BaseWrapperTest extends TestCase
+abstract class BaseTestWrapper extends TestCase
{
/**
- * @return \ByJG\Mail\Envelope
+ * @return Envelope
*/
- public function getBasicEnvelope()
+ public function getBasicEnvelope(): Envelope
{
$envelope = new Envelope(
Util::getFullEmail('from@email.com', "João"),
@@ -22,7 +22,7 @@ public function getBasicEnvelope()
return $envelope;
}
- public function getFullEnvelope()
+ public function getFullEnvelope(): Envelope
{
$envelope = $this->getBasicEnvelope();
$envelope->addTo('to2@email.com', 'Name');
@@ -33,7 +33,7 @@ public function getFullEnvelope()
return $envelope;
}
- public function getAttachmentEnvelope()
+ public function getAttachmentEnvelope(): Envelope
{
$envelope = $this->getFullEnvelope();
$envelope->addAttachment('myname', __DIR__ . '/resources/attachment1.txt', 'text/plain');
@@ -41,7 +41,7 @@ public function getAttachmentEnvelope()
return $envelope;
}
- public function getEmbedImageEnvelope()
+ public function getEmbedImageEnvelope(): Envelope
{
$envelope = $this->getFullEnvelope();
$envelope->addEmbedImage('myname', __DIR__ . '/resources/pixel.gif', 'image/gif');
@@ -49,7 +49,12 @@ public function getEmbedImageEnvelope()
return $envelope;
}
- protected function fixVariableFields($text)
+ /**
+ * @return null|string|string[]
+ *
+ * @psalm-return array|null|string
+ */
+ protected function fixVariableFields($text): array|string|null
{
$text = preg_replace(
[
@@ -70,7 +75,12 @@ protected function fixVariableFields($text)
return $text;
}
- protected function fixRequestBody($text)
+ /**
+ * @return null|string|string[]
+ *
+ * @psalm-return array|null|string
+ */
+ protected function fixRequestBody($text): array|string|null
{
$text = preg_replace(
[
@@ -83,9 +93,9 @@ protected function fixRequestBody($text)
[
'',
'--12345',
- file_get_contents(__DIR__ . "/resources/pixel.gif"),
- file_get_contents(__DIR__ . "/resources/moon.png"),
- file_get_contents(__DIR__ . "/resources/sun.png"),
+ file_get_contents(__DIR__ . "/resources/pixel.gif") ?: '',
+ file_get_contents(__DIR__ . "/resources/moon.png") ?: '',
+ file_get_contents(__DIR__ . "/resources/sun.png") ?: '',
],
$text
);
diff --git a/tests/EnvelopeTest.php b/tests/EnvelopeTest.php
index 0152840..1aa852c 100644
--- a/tests/EnvelopeTest.php
+++ b/tests/EnvelopeTest.php
@@ -1,7 +1,8 @@
object = new Envelope;
@@ -25,12 +27,13 @@ protected function setUp(): void
* Tears down the fixture, for example, closes a network connection.
* This method is called after a test is executed.
*/
+ #[\Override]
protected function tearDown(): void
{
}
- public function testGetFrom()
+ public function testGetFrom(): void
{
$this->object->setFrom('some@email.com');
$this->assertEquals('some@email.com', $this->object->getFrom());
@@ -39,7 +42,7 @@ public function testGetFrom()
$this->assertEquals('"John Doe" ', $this->object->getFrom());
}
- public function testGetTo()
+ public function testGetTo(): void
{
$this->object->addTo('some@email.com');
$this->assertEquals(['some@email.com'], $this->object->getTo());
@@ -51,13 +54,13 @@ public function testGetTo()
$this->assertEquals(['"Only This" '], $this->object->getTo());
}
- public function testGetSubject()
+ public function testGetSubject(): void
{
$this->object->setSubject('Test');
$this->assertEquals('Test', $this->object->getSubject());
}
- public function testGetCC()
+ public function testGetCC(): void
{
$this->object->addCC('some@email.com');
$this->assertEquals(['some@email.com'], $this->object->getCC());
@@ -69,7 +72,7 @@ public function testGetCC()
$this->assertEquals(['"Only This" '], $this->object->getCC());
}
- public function testGetBCC()
+ public function testGetBCC(): void
{
$this->object->addBCC('some@email.com');
$this->assertEquals(['some@email.com'], $this->object->getBCC());
@@ -82,7 +85,7 @@ public function testGetBCC()
}
- public function testGetBody()
+ public function testGetBody(): void
{
$this->object->setBody('
Some title
Other test Break
');
$this->assertEquals('
Some title
Other test Break
', $this->object->getBody());
@@ -90,7 +93,7 @@ public function testGetBody()
}
- public function testGetAttachments()
+ public function testGetAttachments(): void
{
$this->object->addAttachment('name1', '/path/to/file', 'mime/type');
$this->assertEquals(
diff --git a/tests/FakeSenderWrapperTest.php b/tests/FakeSenderTestWrapper.php
similarity index 84%
rename from tests/FakeSenderWrapperTest.php
rename to tests/FakeSenderTestWrapper.php
index 3a8a6fc..76ca88c 100644
--- a/tests/FakeSenderWrapperTest.php
+++ b/tests/FakeSenderTestWrapper.php
@@ -10,7 +10,7 @@
use ByJG\Mail\Wrapper\FakeSenderWrapper;
use ByJG\Util\Uri;
-class FakeSenderWrapperTest extends BaseWrapperTest
+class FakeSenderTestWrapper extends BaseTestWrapper
{
/**
* @param Envelope $envelope
@@ -24,7 +24,7 @@ public function doFakeSend(Envelope $envelope): SendResult
return $wrapper->send($envelope);
}
- public function testBasicEnvelope()
+ public function testBasicEnvelope(): void
{
$envelope = $this->getBasicEnvelope();
@@ -34,7 +34,7 @@ public function testBasicEnvelope()
$this->assertEquals('fake-id-123', $result->id);
}
- public function testFullEnvelope()
+ public function testFullEnvelope(): void
{
$envelope = $this->getFullEnvelope();
@@ -44,7 +44,7 @@ public function testFullEnvelope()
$this->assertEquals('fake-id-123', $result->id);
}
- public function testAttachmentEnvelope()
+ public function testAttachmentEnvelope(): void
{
$envelope = $this->getAttachmentEnvelope();
@@ -54,7 +54,7 @@ public function testAttachmentEnvelope()
$this->assertEquals('fake-id-123', $result->id);
}
- public function testEmbedImageEnvelope()
+ public function testEmbedImageEnvelope(): void
{
$envelope = $this->getEmbedImageEnvelope();
diff --git a/tests/Functional/AmazonSesFunctionalTest.php b/tests/Functional/AmazonSesFunctionalTest.php
index 9272ac9..4e937f3 100644
--- a/tests/Functional/AmazonSesFunctionalTest.php
+++ b/tests/Functional/AmazonSesFunctionalTest.php
@@ -2,15 +2,19 @@
namespace Tests\Functional;
+use ByJG\Mail\Exception\InvalidMailHandlerException;
+use ByJG\Mail\Exception\ProtocolNotRegisteredException;
use ByJG\Mail\MailerFactory;
use ByJG\Mail\Wrapper\AmazonSesWrapper;
+use Override;
class AmazonSesFunctionalTest extends FunctionalBase
{
/**
- * @throws \ByJG\Mail\Exception\InvalidMailHandlerException
- * @throws \ByJG\Mail\Exception\ProtocolNotRegisteredException
+ * @throws InvalidMailHandlerException
+ * @throws ProtocolNotRegisteredException
*/
+ #[Override]
public function setUp(): void
{
MailerFactory::registerMailer(AmazonSesWrapper::class);
diff --git a/tests/Functional/FunctionalBase.php b/tests/Functional/FunctionalBase.php
index 09b30ac..0bdf8b2 100644
--- a/tests/Functional/FunctionalBase.php
+++ b/tests/Functional/FunctionalBase.php
@@ -3,21 +3,26 @@
namespace Tests\Functional;
use ByJG\Mail\Envelope;
+use ByJG\Mail\Exception\ProtocolNotRegisteredException;
use ByJG\Mail\MailerFactory;
+use ByJG\Mail\Wrapper\MailWrapperInterface;
+use ByJG\Util\Uri;
+use Override;
use PHPUnit\Framework\TestCase;
abstract class FunctionalBase extends TestCase
{
- protected $uri;
- protected $from;
- protected $toEmail;
- protected $mailer;
- protected $envelope;
- protected $mailerName;
+ protected Uri|string|false $uri;
+ protected string|null $from;
+ protected string|null $toEmail;
+ protected MailWrapperInterface|null $mailer;
+ protected Envelope|null $envelope;
+ protected string $mailerName;
/**
- * @throws \ByJG\Mail\Exception\ProtocolNotRegisteredException
+ * @throws ProtocolNotRegisteredException
*/
+ #[Override]
public function setUp(): void
{
if (!$this->uri || !$this->from || !$this->toEmail) {
@@ -40,6 +45,7 @@ public function setUp(): void
);
}
+ #[Override]
public function tearDown(): void
{
$this->mailer = null;
@@ -48,12 +54,15 @@ public function tearDown(): void
$this->envelope = null;
}
+ /**
+ * @return void
+ */
public function testSendEmail()
{
if (empty($this->mailer)) {
$this->markTestSkipped('Environment Variables not set');
- return;
}
- $this->assertTrue($this->mailer->send($this->envelope));
+ $result = $this->mailer->send($this->envelope);
+ $this->assertTrue($result->success);
}
}
diff --git a/tests/Functional/MailgunFunctionalTest.php b/tests/Functional/MailgunFunctionalTest.php
index 824f73c..f138228 100644
--- a/tests/Functional/MailgunFunctionalTest.php
+++ b/tests/Functional/MailgunFunctionalTest.php
@@ -2,15 +2,19 @@
namespace Tests\Functional;
+use ByJG\Mail\Exception\InvalidMailHandlerException;
+use ByJG\Mail\Exception\ProtocolNotRegisteredException;
use ByJG\Mail\MailerFactory;
use ByJG\Mail\Wrapper\MailgunApiWrapper;
+use Override;
class MailgunFunctionalTest extends FunctionalBase
{
/**
- * @throws \ByJG\Mail\Exception\InvalidMailHandlerException
- * @throws \ByJG\Mail\Exception\ProtocolNotRegisteredException
+ * @throws InvalidMailHandlerException
+ * @throws ProtocolNotRegisteredException
*/
+ #[Override]
public function setUp(): void
{
MailerFactory::registerMailer(MailgunApiWrapper::class);
diff --git a/tests/Functional/PHPMailerFunctionalTest.php b/tests/Functional/PHPMailerFunctionalTest.php
index d51cca2..9875f3e 100644
--- a/tests/Functional/PHPMailerFunctionalTest.php
+++ b/tests/Functional/PHPMailerFunctionalTest.php
@@ -2,15 +2,19 @@
namespace Tests\Functional;
+use ByJG\Mail\Exception\InvalidMailHandlerException;
+use ByJG\Mail\Exception\ProtocolNotRegisteredException;
use ByJG\Mail\MailerFactory;
use ByJG\Mail\Wrapper\PHPMailerWrapper;
+use Override;
class PHPMailerFunctionalTest extends FunctionalBase
{
/**
- * @throws \ByJG\Mail\Exception\InvalidMailHandlerException
- * @throws \ByJG\Mail\Exception\ProtocolNotRegisteredException
+ * @throws InvalidMailHandlerException
+ * @throws ProtocolNotRegisteredException
*/
+ #[Override]
public function setUp(): void
{
MailerFactory::registerMailer(PHPMailerWrapper::class);
diff --git a/tests/MailUtilTest.php b/tests/MailUtilTest.php
index 9e83080..5aaadb2 100644
--- a/tests/MailUtilTest.php
+++ b/tests/MailUtilTest.php
@@ -1,5 +1,7 @@
assertTrue(Util::isValidEmail(self::EMAIL_OK));
- $this->assertTrue(!Util::isValidEmail(self::EMAIL_NOK_1));
- $this->assertTrue(!Util::isValidEmail(self::EMAIL_NOK_2));
- $this->assertTrue(!Util::isValidEmail(self::EMAIL_NOK_3));
- $this->assertTrue(!Util::isValidEmail(self::EMAIL_NOK_4));
- $this->assertTrue(!Util::isValidEmail(self::EMAIL_NOK_5));
+ $this->assertFalse(Util::isValidEmail(self::EMAIL_NOK_1));
+ $this->assertFalse(Util::isValidEmail(self::EMAIL_NOK_2));
+ $this->assertFalse(Util::isValidEmail(self::EMAIL_NOK_3));
+ $this->assertFalse(Util::isValidEmail(self::EMAIL_NOK_4));
+ $this->assertFalse(Util::isValidEmail(self::EMAIL_NOK_5));
}
- function test_GetFullEmailName()
+ function test_GetFullEmailName(): void
{
$this->assertEquals(Util::getFullEmail("joao@server.com.br", "Joao"), '"Joao" ');
$this->assertEquals(Util::getFullEmail("joao@server.com.br", ""), 'joao@server.com.br');
$this->assertEquals(Util::getFullEmail("joao@server.com.br"), 'joao@server.com.br');
}
- function test_GetEmailPair()
+ function test_GetEmailPair(): void
{
$pair = Util::decomposeEmail('"Name" ');
$this->assertEquals($pair["name"], 'Name');
diff --git a/tests/MailerWrapperTest.php b/tests/MailerWrapperTest.php
index 15c5509..15b642b 100644
--- a/tests/MailerWrapperTest.php
+++ b/tests/MailerWrapperTest.php
@@ -1,10 +1,11 @@
expectException(InvalidMailHandlerException::class);
MailerFactory::registerMailer(MailerWrapperTest::class);
}
/**
- * @throws \ByJG\Mail\Exception\InvalidMailHandlerException
- * @throws \ByJG\Mail\Exception\ProtocolNotRegisteredException
+ * @throws InvalidMailHandlerException
+ * @throws ProtocolNotRegisteredException
*/
- public function testCreate()
+ public function testCreate(): void
{
MailerFactory::registerMailer(PHPMailerWrapper::class);
MailerFactory::create('smtp://localhost');
@@ -50,10 +51,10 @@ public function testCreate()
}
/**
- * @throws \ByJG\Mail\Exception\ProtocolNotRegisteredException
- * @throws \ByJG\Mail\Exception\InvalidMailHandlerException
+ * @throws ProtocolNotRegisteredException
+ * @throws InvalidMailHandlerException
*/
- public function testCreateFail()
+ public function testCreateFail(): void
{
$this->expectException(ProtocolNotRegisteredException::class);
MailerFactory::registerMailer(PHPMailerWrapper::class);
diff --git a/tests/MailgunWrapperTest.php b/tests/MailgunTestWrapper.php
similarity index 94%
rename from tests/MailgunWrapperTest.php
rename to tests/MailgunTestWrapper.php
index 9054140..e4bcdc1 100644
--- a/tests/MailgunWrapperTest.php
+++ b/tests/MailgunTestWrapper.php
@@ -16,7 +16,7 @@
use ByJG\WebRequest\Psr7\MemoryStream;
use Psr\Http\Client\ClientExceptionInterface;
-class MailgunWrapperTest extends BaseWrapperTest
+class MailgunTestWrapper extends BaseTestWrapper
{
/**
@@ -40,7 +40,7 @@ public function doMockedRequest(Envelope $envelope, MockClient $mock): SendResul
* @throws RequestException
* @throws MessageException
*/
- public function testGetRequest()
+ public function testGetRequest(): void
{
$wrapper = new MailgunApiWrapper(new Uri('mailgun://YOUR_API_KEY@YOUR_DOMAIN'));
$request = $wrapper->getRequestObject();
@@ -56,7 +56,7 @@ public function testGetRequest()
* @throws InvalidEMailException
* @throws MessageException
*/
- public function testBasicEnvelope()
+ public function testBasicEnvelope(): void
{
$expectedResponse = new Response(200);
$expectedResponse = $expectedResponse->withBody(new MemoryStream('{"id":"12345"}'));
@@ -80,7 +80,7 @@ public function testBasicEnvelope()
* @throws ClientExceptionInterface
* @throws MessageException
*/
- public function testFullEnvelope()
+ public function testFullEnvelope(): void
{
$expectedResponse = new Response(200);
$expectedResponse = $expectedResponse->withBody(new MemoryStream('{"id":"12345"}'));
@@ -104,7 +104,7 @@ public function testFullEnvelope()
* @throws InvalidEMailException
* @throws MessageException
*/
- public function testAttachmentEnvelope()
+ public function testAttachmentEnvelope(): void
{
$expectedResponse = new Response(200);
$expectedResponse = $expectedResponse->withBody(new MemoryStream('{"id":"12345"}'));
@@ -128,7 +128,7 @@ public function testAttachmentEnvelope()
* @throws ClientExceptionInterface
* @throws MessageException
*/
- public function testEmbedImageEnvelope()
+ public function testEmbedImageEnvelope(): void
{
$expectedResponse = new Response(200);
$expectedResponse = $expectedResponse->withBody(new MemoryStream('{"id":"12345"}'));
diff --git a/tests/MockSender.php b/tests/MockSender.php
index d361ca4..704bd9e 100644
--- a/tests/MockSender.php
+++ b/tests/MockSender.php
@@ -6,10 +6,10 @@
class MockSender
{
- public $result;
+ public string $result;
// AmazonSes
- public function sendRawEmail($raw)
+ public function sendRawEmail(string $raw): Result
{
$this->result = $raw;
@@ -19,7 +19,7 @@ public function sendRawEmail($raw)
}
// Mailgun Wrapper
- public function postMultiPartForm($message)
+ public function postMultiPartForm($message): string
{
$this->result = $message;
return '{"id": "123445"}';
diff --git a/tests/PHPMailerWrapperTest.php b/tests/PHPMailerTestWrapper.php
similarity index 82%
rename from tests/PHPMailerWrapperTest.php
rename to tests/PHPMailerTestWrapper.php
index d0c3e0a..f23aa6a 100644
--- a/tests/PHPMailerWrapperTest.php
+++ b/tests/PHPMailerTestWrapper.php
@@ -2,6 +2,7 @@
namespace Tests;
+use ByJG\Mail\Envelope;
use ByJG\Mail\Exception\InvalidEMailException;
use ByJG\Mail\Exception\MailApiException;
use ByJG\Mail\Override\PHPMailerOverride;
@@ -9,16 +10,16 @@
use ByJG\Util\Uri;
use PHPMailer\PHPMailer\Exception;
-class PHPMailerWrapperTest extends BaseWrapperTest
+class PHPMailerTestWrapper extends BaseTestWrapper
{
/**
- * @param $envelope
+ * @param Envelope $envelope
* @return array
* @throws Exception
* @throws InvalidEMailException
* @throws MailApiException
*/
- public function doMockedRequest($envelope): array
+ public function doMockedRequest(Envelope $envelope): array
{
$mock = $this->getMockBuilder(PHPMailerOverride::class)
->onlyMethods(['send', 'getLastMessageID'])
@@ -47,7 +48,7 @@ public function doMockedRequest($envelope): array
return [$mock, $sendResult];
}
- protected function send($envelope, $rawEmail)
+ protected function send(Envelope $envelope, string $rawEmail): void
{
[$mock, $sendResult] = $this->doMockedRequest($envelope);
$expected = $this->fixVariableFields(file_get_contents(__DIR__ . '/resources/' . $rawEmail . '.eml'));
@@ -58,25 +59,25 @@ protected function send($envelope, $rawEmail)
$this->assertEquals('mocked-message-id', $sendResult->id);
}
- public function testBasicEnvelope()
+ public function testBasicEnvelope(): void
{
$envelope = $this->getBasicEnvelope();
$this->send($envelope, 'basicenvelope');
}
- public function testFullEnvelope()
+ public function testFullEnvelope(): void
{
$envelope = $this->getFullEnvelope();
$this->send($envelope, 'fullenvelope');
}
- public function testAttachmentEnvelope()
+ public function testAttachmentEnvelope(): void
{
$envelope = $this->getAttachmentEnvelope();
$this->send($envelope, 'attachmentenvelope');
}
- public function testEmbedImageEnvelope()
+ public function testEmbedImageEnvelope(): void
{
$envelope = $this->getEmbedImageEnvelope();
$this->send($envelope, 'embedenvelope');
diff --git a/tests/UriTest.php b/tests/UriTest.php
index 75b63ea..d3c1add 100644
--- a/tests/UriTest.php
+++ b/tests/UriTest.php
@@ -1,13 +1,13 @@
assertEquals('smtp', $object->getScheme());