Skip to content

Commit

Permalink
Inline css when mail has attachment part
Browse files Browse the repository at this point in the history
  • Loading branch information
ajohnson6494 committed Feb 15, 2023
1 parent ae75ef7 commit a41e707
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 105 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
php-versions: ['8.1', '8.0']
php-versions: ['8.2', '8.1', '8.0']
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v1
Expand All @@ -16,22 +16,23 @@ jobs:
php-version: ${{ matrix.php-versions }}
extensions: dom, libxml, mbstring, intl, xml, fileinfo, zip
coverage: xdebug
tools: prestissimo
- name: Get composer cache directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache composer dependencies
uses: actions/cache@v1
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install Composer dependencies
run: composer install --no-ansi --no-interaction --no-progress --optimize-autoloader
- name: Setup Problem Matchers for PHPUnit
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
- name: Test with phpunit
run: vendor/bin/phpunit --coverage-text
- name: Check for vulnerabilities
run: composer security-checker
composer-normalize:
runs-on: ubuntu-latest
steps:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Laravel Symfony Mailer CSS Inliner
Most email clients won't render CSS (on a `<link>` or a `<style>`). The solution is inline your CSS directly on the HTML. Doing this by hand easily turns into unmantainable templates.
The goal of this package is to automate the process of inlining that CSS before sending the emails.

## Instalation and compatability
## Installation and compatability

Requires PHP 8.1 and Laravel 9.0 or higher.

Expand Down
7 changes: 7 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"tijsverkoyen/css-to-inline-styles": "~2.2"
},
"require-dev": {
"enlightn/security-checker": "^1.10",
"phpunit/phpunit": "^9.0 || ^10",
"symfony/mailer": "^6.0"
},
Expand All @@ -45,5 +46,11 @@
"psr-4": {
"Tests\\": "tests/"
}
},
"scripts": {
"security-checker": "security-checker security:check"
},
"scripts-descriptions": {
"security-checker": "Checks if your application uses dependencies with known security vulnerabilities."
}
}
55 changes: 26 additions & 29 deletions src/CssInlinerPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
namespace ajohnson6494\LaravelSymfonyMailerCssInliner;

use DOMDocument;
use Symfony\Component\Mime\Message;
use Symfony\Component\Mime\Part\TextPart;
use Illuminate\Mail\Events\MessageSending;
use Symfony\Component\Mime\Part\AbstractPart;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mailer\Event\MessageEvent;
use Symfony\Component\Mime\Part\AbstractPart;
use Symfony\Component\Mime\Part\AbstractMultipartPart;
use Symfony\Component\Mime\Part\Multipart\AlternativePart;
use Symfony\Component\Mime\Part\Multipart\MixedPart;
use Symfony\Component\Mime\Part\TextPart;
use TijsVerkoyen\CssToInlineStyles\CssToInlineStyles;
use Symfony\Component\Mime\Part\Multipart\AlternativePart;

class CssInlinerPlugin
{
Expand All @@ -29,28 +30,37 @@ public function handle(MessageSending $event): void
{
$message = $event->message;

if (!$message instanceof Message) {
if (!$message instanceof Email) {
return;
}

$this->handleSymfonyMessage($message);
$this->handleSymfonyEmail($message);
}

public function handleSymfonyEvent(MessageEvent $event): void
{
$message = $event->getMessage();

if (!$message instanceof Message) {
if (!$message instanceof Email) {
return;
}

$this->handleSymfonyMessage($message);
$this->handleSymfonyEmail($message);
}

private function processPart(AbstractPart $part): AbstractPart
{
if ($part instanceof TextPart && $part->getMediaType() === 'text' && $part->getMediaSubtype() === 'html') {
return $this->processHtmlTextPart($part);
} else if ($part instanceof AbstractMultipartPart) {
$part_class = get_class($part);
$parts = [];

foreach ($part->getParts() as $childPart) {
$parts[] = $this->processPart($childPart);
}

return new $part_class(...$parts);
}

return $part;
Expand All @@ -76,7 +86,7 @@ private function processHtmlTextPart(TextPart $part): TextPart
return new TextPart($bodyString, $part->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8', 'html');
}

private function handleSymfonyMessage(Message $message): void
private function handleSymfonyEmail(Email $message): void
{
$body = $message->getBody();

Expand All @@ -87,26 +97,13 @@ private function handleSymfonyMessage(Message $message): void
if ($body instanceof TextPart) {
$message->setBody($this->processPart($body));
} elseif ($body instanceof AlternativePart || $body instanceof MixedPart) {
$originalParts = $body->getParts();
$allParts = [];

foreach($originalParts as $part) {
if ($part->getMediaType() === "multipart") {
/** @var \Symfony\Component\Mime\Part\Multipart $part */
foreach ($part->getParts() as $p) {
$allParts[] = $p;
}
} else {
$allParts[] = $part;
}
}

$message->setBody(new AlternativePart(
...array_map(
fn (AbstractPart $part) => $this->processPart($part),
$allParts
)
));
$part_type = get_class($body);
$message->setBody(new $part_type(
...array_map(
fn (AbstractPart $part) => $this->processPart($part),
$body->getParts()
)
));
}
}

Expand Down
Loading

0 comments on commit a41e707

Please sign in to comment.