erwane/whep-client

Webhooks handler for emailing providers.

2.2.0 2025-08-12 20:40 UTC

This package is auto-updated.

Last update: 2025-08-13 09:57:59 UTC


README

Software License codecov CI Packagist Downloads Packagist Version

This is the base project to easily handle webhooks sent by different emailing providers and uniformizing in a comprehensive object.

This project is not made to be used alone, you need to pick your providers handlers corresponding to your project.

Available providers handlers

Provider Package
Brevo erwane/whep-brevo
Mailgun erwane/whep-mailgun
Mailjet erwane/whep-mailjet
Postal erwane/whep-postal

Usage

composer require erwane/whep-<provider>
use WHEP\Factory;  
use WHEP\Exception\SecurityException;  
use WHEP\Exception\WHEPException;  
use WHEP\ProviderInterface;  

try {
    $provider = Factory::provider('<provider>', [
        'client_ip' => $_SERVER['REMOTE_ADDR'] ?? null, // Use your framework correct method to get the client ip.
        'callbacks' => [
            ProviderInterface::EVENT_BLOCKED => [$this, 'callbackInvalidate'],
            ProviderInterface::EVENT_BOUNCE_HARD => [$this, 'callbackInvalidate'],
            ProviderInterface::EVENT_BOUNCE_QUOTA => [$this, 'callbackUnsub'],
        ],
    ]);

    // process the data.
    $provider->process($webhookData);
    
    // Data available from provider getters.
    $recipient = $provider->getRecipient();
    
    // Launch callback
    $provider->callback();
} catch (SecurityException $e) {
    // log ?
} catch (WHEPException $e) {
    // log ?
}

Options

You can pass options to Factory::provider('<provider>', $options) method.
All available options are:

  • client_ip: The client IP who request your url. Default null
  • allowed_ip: Array of IPv4/IPv6 network (range) and allowed IP. Default depends on provider.
  • check_ip: Set to false to bypass security IP check. Default is false.
  • signing_key: Your provider private key to validate request came from trusted provider. Default null
  • callbacks: You callable you want to be called, depends on event type.

Security

Except if your webhook url has a security token, you can't ensure the webhook really came from trusted provider.
Some providers use a signing key to validate data or provide an IP addresses list.

IP validation

When provider publish his IP addresses, you should pass the webhook client IP to the provider.

Factory::provider('mailjet', ['client_ip' => $_SERVER['REMOTE_ADDR'] ?? null]);

When provider is self-hosted, like Postal, you can pass your postal server IP.

Factory::provider('postal', [
    'client_ip' => $_SERVER['REMOTE_ADDR'] ?? null,
    'allowed_ip' => [
        '10.0.0.1',
        'fe80::0023:1',
        '192.168.0.1/24',
    ],
]);

You can bypass IP check with check_ip sets to false.

Factory::provider('mailjet', ['check_ip' => false]);

Signing key

When provider support signing key, you can pass your private key with signing_key option.

Factory::provider('mailgun', ['signing_key' => 'my-private-signing-key']);

The validation is done during ProviderInterface::process()

Callbacks

Your callback method are cast when $provider->callback() is called (you decide when). See Event type & Callbacks section for details.

Factory::provider('<provider>', ['callbacks' => [ProviderInterface::EVENT_UNSUB => [$this, 'callbackUnsub']]]);

Event type & Callbacks

You can configure one callback by event type. Available callbacks are:

Event Why event was emitted
ProviderInterface::EVENT_REQUEST You send an e-mail to your provider.
ProviderInterface::EVENT_DEFERRED The send was deferred by provider.
ProviderInterface::EVENT_BLOCKED The recipient e-mail is in provider blocklist.
ProviderInterface::EVENT_SENT E-mail was sent.
ProviderInterface::EVENT_BOUNCE_SOFT E-mail receive a soft-bounce (4xx) with reason.
ProviderInterface::EVENT_BOUNCE_QUOTA Like BOUNCE_SOFT but quota problem detected.
ProviderInterface::EVENT_BOUNCE_HARD E-mail receive a hard-bounce (5xx) with reason.
ProviderInterface::EVENT_OPENED E-mail was opened.
ProviderInterface::EVENT_CLICK A link was clicked.
ProviderInterface::EVENT_ABUSE Recipient report your e-mail as abuse.
ProviderInterface::EVENT_UNSUB Recipient want to unsubscribed from you list.
ProviderInterface::EVENT_ERROR Provider error.

Methods

ProviderInterface has the following methods:

getName()

Return provider name.

echo $provider->getName();

getTime()

Get event time as \DateTimeInterface. This represents when hook was received, not event time.

$time = $provider->getTime();

getType()

Return event type. See Event type & Callbacks for all types.

if ($provider->getType() === \WHEP\ProviderInterface::EVENT_UNSUB) {
    // Do something
}

getRecipient()

Return event related e-mail recipient.

echo $provider->getRecipient();

getDetails()

Return provider event details (or reason).

echo $provider->getDetails();

getSmtpResponse()

Return recipient MX SMTP response.

echo $provider->getSmtpResponse();

getUrl()

Return url of clicked link. Available for \WHEP\ProviderInterface::EVENT_CLICK only.
Some providers (mailgun) do not return this information.

echo $provider->getUrl();

getRaw()

Return event raw data as array by default. Return as json if $asJson is true.

$raw = $provider->getRaw();

// raw data in json format.
echo $provider->getRaw(true);

process()

Process the webhook data. This method is chainable.

$provider = \WHEP\Factory::provider('mailgun')
    ->process($webhookData);

callback()

Run you related event type callable if configured.

// This will process data and call self::callbackUnsub($provider) if event is unsub.
$provider = \WHEP\Factory::provider('mailgun', [
    'callbacks' => [
        \WHEP\ProviderInterface::EVENT_UNSUB => [$this, 'callbackUnsub'],
    ],
])
    ->process($webhookData)
    ->callback();

securityChecked()

Return true if security was checked. Default to false.

if (!$provider->securityChecked()) {
    // Your webhook url deserve security.
}