PHP code example of rlnks / php-mail-audit

1. Go to this page and download the library: Download rlnks/php-mail-audit library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

rlnks / php-mail-audit example snippets


use MailAudit\MailAudit;

$html = file_get_contents('path/to/template.html');

$audit  = new MailAudit();
$result = $audit->analyze($html);

echo "Score: {$result['score']}/100\n";
echo "Issues: {$result['summary']['total_issues']}  |  Passed: {$result['summary']['passed']}\n\n";

foreach ($result['insights'] as $insight) {
    echo "[{$insight['severity']}] {$insight['message']}\n";
    echo "  Fix: {$insight['fix']}\n\n";
}

foreach ($result['passed'] as $check) {
    echo "[pass] {$check['message']}\n";
}

$audit = new MailAudit(
    config: [
        'auto_update' => true,                        // enable remote KB sync
        'ttl_days'    => 7,                           // cache TTL in days
        'endpoint'    => 'https://kb.example.com/rules.json',
        'api_key'     => getenv('MAILAUDIT_API_KEY'), // null = free tier
        'cache_path'  => '/tmp/mailaudit-rules.json', // writable path
    ],
    locale: 'en',          // single locale — 'en', 'fr', 'es', 'de', 'pt'
    // locale: ['en', 'fr'], // or multiple locales at once
);

// config/mailaudit.php
return [
    'auto_update' => true,
    'ttl_days'    => 7,
    'endpoint'    => getenv('MAILAUDIT_ENDPOINT'),
    'api_key'     => getenv('MAILAUDIT_API_KEY'),
    'cache_path'  => __DIR__ . '/../var/mailaudit-rules.json',
];

// usage
$audit = new MailAudit(

$result = $audit->analyze(string $html): array

// From a string
$result = $audit->analyze('<div style="display:flex;">Hello</div>');

// From a file
$result = $audit->analyze(file_get_contents('emails/welcome.html'));

// From a rendered template (e.g. Twig)
$html   = $twig->render('emails/welcome.html.twig', $data);
$result = $audit->analyze($html);

[
    'score'    => 81,          // int, 0–100
    'insights' => [ ... ],     // triggered rules (issues)
    'passed'   => [ ... ],     // rules that passed with a positive check message
    'summary'  => [ ... ],     // aggregate counts
]

[
    'id'               => 'no-flexbox',
    'severity'         => 'error',          // 'error' | 'warning' | 'info'
    'weight'           => 15,               // nominal weight of the rule
    'message'          => 'Flexbox is not supported in Outlook desktop...',
    'fix'              => 'Replace flexbox with HTML table-based layout...',
    'affected_clients' => [
        'outlook_desktop' => ['supported' => false, 'versions' => 'all'],
        'gmail_web'       => ['supported' => false, 'versions' => '< 2022'],
        'apple_mail'      => ['supported' => true],
    ],
    'tags'      => ['css', 'layout'],
    'locations' => [
        ['line' => 12, 'column' => 5,  'offset_start' => 450,  'offset_end' => 471],
        ['line' => 34, 'column' => 9,  'offset_start' => 1205, 'offset_end' => 1226],
    ],
]

// Reconstruct the matched snippet from offset
$snippet = substr($html, $loc['offset_start'], $loc['offset_end'] - $loc['offset_start']);

// new MailAudit([], ['en', 'fr'])
'message' => [
    'en' => 'Flexbox is not supported in Outlook desktop...',
    'fr' => 'Flexbox n\'est pas supporté dans Outlook desktop...',
]

[
    'id'       => 'no-flexbox',
    'severity' => 'error',      // severity the rule would have had if triggered
    'message'  => 'No flexbox layout detected — good compatibility with Outlook desktop.',
    'tags'     => ['css', 'layout'],
]

[
    'total_rules_checked' => 56,  // total rules evaluated
    'total_issues'        => 3,   // rules that fired
    'errors'              => 1,   // severity = error
    'warnings'            => 1,   // severity = warning
    'infos'               => 1,   // severity = info
    'passed'              => 9,   // rules that passed with a success message
]

$audit = new MailAudit(locale: 'fr'); // or 'es', 'de', 'pt'

$result = $audit->analyze($html);
// $result['insights'][0]['message'] → string in French
// $result['insights'][0]['fix']     → string in French

$audit = new MailAudit(locale: ['en', 'fr']);

$result = $audit->analyze($html);
// $result['insights'][0]['message'] → ['en' => '...', 'fr' => '...']
// $result['insights'][0]['fix']     → ['en' => '...', 'fr' => '...']
// $result['passed'][0]['message']   → ['en' => '...', 'fr' => '...']

$audit = new MailAudit([
    'auto_update' => true,
    'ttl_days'    => 7,                                        // re-fetch after 7 days
    'endpoint'    => 'https://kb.mailaudit.io/rules.json',
    'api_key'     => getenv('MAILAUDIT_API_KEY'),              // optional, pro tier
    'cache_path'  => __DIR__ . '/var/mailaudit-rules.json',    // must be writable
]);

use MailAudit\Loader\RuleLoader;
use MailAudit\Analysis\RuleEngine;
use MailAudit\Analysis\ScoringEngine;
use MailAudit\Feedback\FeedbackGenerator;

$bundled = (new RuleLoader())->load();
$custom  = [json_decode(file_get_contents('rules/no-video.json'), true)];
$rules   = array_merge($bundled, $custom);

$triggered = (new RuleEngine($rules))->analyze($html);
$score     = (new ScoringEngine())->calculate($triggered);
$insights  = (new FeedbackGenerator('en'))->generate($triggered);

use MailAudit\Detection\DetectorInterface;

class MjmlTagDetector implements DetectorInterface
{
    public function matches(string $html, array $detection): bool
    {
        foreach ($detection['tags'] ?? [] as $tag) {
            if (str_contains($html, "<mj-{$tag}")) {
                return true;
            }
        }
        return false;
    }
}

use MailAudit\Detection\DetectorFactory;

DetectorFactory::register('mjml_tag', MjmlTagDetector::class);

use MailAudit\MailAudit;

$result = (new MailAudit())->analyze(file_get_contents('email.html'));

if ($result['score'] < 80) {
    foreach ($result['insights'] as $insight) {
        if ($insight['severity'] === 'error') {
            throw new RuntimeException("Email has blocking issues: {$insight['message']}");
        }
    }
}

// config/services.yaml
services:
    MailAudit\MailAudit:
        arguments:
            $config:
                auto_update: true
                ttl_days: 7
                endpoint: '%env(MAILAUDIT_ENDPOINT)%'
                api_key: '%env(MAILAUDIT_API_KEY)%'
                cache_path: '%kernel.cache_dir%/mailaudit-rules.json'

// In a service or controller
public function __construct(private MailAudit $audit) {}

public function preview(string $html): array
{
    return $this->audit->analyze($html);
}

// config/mailaudit.php
return [
    'auto_update' => true,
    'ttl_days'    => 7,
    'endpoint'    => env('MAILAUDIT_ENDPOINT'),
    'api_key'     => env('MAILAUDIT_API_KEY'),
    'cache_path'  => storage_path('app/mailaudit-rules.json'),
];

// AppServiceProvider
$this->app->singleton(\MailAudit\MailAudit::class, fn() =>
    new \MailAudit\MailAudit(config('mailaudit'))
);
bash
composer 
json
{
  "message": {
    "en": "Flexbox is not supported in Outlook.",
    "fr": "Flexbox n'est pas supporté dans Outlook.",
    "de": "Flexbox wird in Outlook nicht unterstützt."
  },
  "fix": {
    "en": "Use HTML tables for layout.",
    "fr": "Utilisez des tables HTML pour la mise en page.",
    "de": "Verwenden Sie HTML-Tabellen für das Layout."
  }
}
bash
vendor/bin/mailaudit sync --config=config/mailaudit.php
bash
vendor/bin/mailaudit sync --config=config/mailaudit.php --dry-run
json
{
  "id": "no-video",
  "version": "1.0",
  "updated_at": "2026-05-09",
  "source": "https://www.caniemail.com/features/html-video/",
  "tier": "free",
  "severity": "error",
  "weight": 12,
  "tags": ["html", "media"],
  "detection": {
    "type": "html_tag",
    "patterns": ["video"]
  },
  "affected_clients": {
    "outlook_desktop": { "supported": false, "versions": "all" },
    "gmail_web": { "supported": false }
  },
  "message": {
    "en": "<video> elements are not supported in Outlook or Gmail.",
    "fr": "Les éléments <video> ne sont pas supportés dans Outlook ni Gmail."
  },
  "fix": {
    "en": "Use a linked image (GIF or static) as a fallback for video content.",
    "fr": "Utiliser une image liée (GIF ou statique) comme fallback pour le contenu vidéo."
  }
}
yaml
- name: Audit email templates
  run: |
    php -r "
       \$audit->analyze(file_get_contents('templates/welcome.html'));
      if (\$result['score'] < 70) {
          echo 'Email quality score too low: ' . \$result['score'] . '/100\n';
          exit(1);
      }
      echo 'Score: ' . \$result['score'] . "/100 — OK\n";
    "