added mailgun module

This commit is contained in:
Bachir Soussi Chiadmi
2016-07-19 17:52:15 +02:00
parent c64551f50c
commit deae7e0b59
42 changed files with 3659 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
<?php
namespace Mailgun\Connection\Exceptions;
class GenericHTTPError extends \Exception
{
protected $httpResponseCode;
protected $httpResponseBody;
public function __construct($message=null, $response_code=null, $response_body=null, $code=0, \Exception $previous=null) {
parent::__construct($message, $code, $previous);
$this->httpResponseCode = $response_code;
$this->httpResponseBody = $response_body;
}
public function getHttpResponseCode() {
return $this->httpResponseCode;
}
public function getHttpResponseBody() {
return $this->httpResponseBody;
}
}
?>

View File

@@ -0,0 +1,4 @@
<?php
namespace Mailgun\Connection\Exceptions;
class InvalidCredentials extends \Exception{}

View File

@@ -0,0 +1,4 @@
<?php
namespace Mailgun\Connection\Exceptions;
class MissingEndpoint extends \Exception{}

View File

@@ -0,0 +1,4 @@
<?php
namespace Mailgun\Connection\Exceptions;
class MissingRequiredParameters extends \Exception{}

View File

@@ -0,0 +1,4 @@
<?php
namespace Mailgun\Connection\Exceptions;
class NoDomainsConfigured extends \Exception{}

View File

@@ -0,0 +1,326 @@
<?PHP
namespace Mailgun\Connection;
use GuzzleHttp\Psr7\MultipartStream;
use GuzzleHttp\Psr7\Request;
use Http\Client\HttpClient;
use Http\Discovery\HttpClientDiscovery;
use Mailgun\Connection\Exceptions\GenericHTTPError;
use Mailgun\Connection\Exceptions\InvalidCredentials;
use Mailgun\Connection\Exceptions\MissingRequiredParameters;
use Mailgun\Connection\Exceptions\MissingEndpoint;
use Mailgun\Constants\Api;
use Mailgun\Constants\ExceptionMessages;
use Psr\Http\Message\ResponseInterface;
/**
* This class is a wrapper for the Guzzle (HTTP Client Library).
*/
class RestClient
{
/**
* Your API key
* @var string
*/
private $apiKey;
/**
* @var HttpClient
*/
protected $httpClient;
/**
* @var string
*/
protected $apiHost;
/**
* The version of the API to use
* @var string
*/
protected $apiVersion = 'v2';
/**
* If we should use SSL or not
* @var bool
*/
protected $sslEnabled = true;
/**
* @param string $apiKey
* @param string $apiHost
* @param HttpClient $httpClient
*/
public function __construct($apiKey, $apiHost, HttpClient $httpClient = null)
{
$this->apiKey = $apiKey;
$this->apiHost = $apiHost;
$this->httpClient = $httpClient;
}
/**
* @param string $method
* @param string $uri
* @param array $body
* @param array $files
* @param array $headers
*
* @return \stdClass
*
* @throws GenericHTTPError
* @throws InvalidCredentials
* @throws MissingEndpoint
* @throws MissingRequiredParameters
*/
protected function send($method, $uri, $body = null, $files = [], array $headers = [])
{
$headers['User-Agent'] = Api::SDK_USER_AGENT.'/'.Api::SDK_VERSION;
$headers['Authorization'] = 'Basic '.base64_encode(sprintf('%s:%s', Api::API_USER, $this->apiKey));
if (!empty($files)) {
$body = new MultipartStream($files);
$headers['Content-Type'] = 'multipart/form-data; boundary='.$body->getBoundary();
}
$request = new Request($method, $this->getApiUrl($uri), $headers, $body);
$response = $this->getHttpClient()->sendRequest($request);
return $this->responseHandler($response);
}
/**
* @param string $endpointUrl
* @param array $postData
* @param array $files
*
* @return \stdClass
*
* @throws GenericHTTPError
* @throws InvalidCredentials
* @throws MissingEndpoint
* @throws MissingRequiredParameters
*/
public function post($endpointUrl, $postData = array(), $files = array())
{
$postFiles = [];
$fields = ['message', 'attachment', 'inline'];
foreach ($fields as $fieldName) {
if (isset($files[$fieldName])) {
if (is_array($files[$fieldName])) {
foreach ($files[$fieldName] as $file) {
$postFiles[] = $this->prepareFile($fieldName, $file);
}
} else {
$postFiles[] = $this->prepareFile($fieldName, $files[$fieldName]);
}
}
}
$postDataMultipart = [];
foreach ($postData as $key => $value) {
if (is_array($value)) {
foreach ($value as $subValue) {
$postDataMultipart[] = [
'name' => $key,
'contents' => $subValue,
];
}
} else {
$postDataMultipart[] = [
'name' => $key,
'contents' => $value,
];
}
}
return $this->send('POST', $endpointUrl, [], array_merge($postDataMultipart, $postFiles));
}
/**
* @param string $endpointUrl
* @param array $queryString
*
* @return \stdClass
*
* @throws GenericHTTPError
* @throws InvalidCredentials
* @throws MissingEndpoint
* @throws MissingRequiredParameters
*/
public function get($endpointUrl, $queryString = array())
{
return $this->send('GET', $endpointUrl.'?'.http_build_query($queryString));
}
/**
* @param string $endpointUrl
*
* @return \stdClass
*
* @throws GenericHTTPError
* @throws InvalidCredentials
* @throws MissingEndpoint
* @throws MissingRequiredParameters
*/
public function delete($endpointUrl)
{
return $this->send('DELETE', $endpointUrl);
}
/**
* @param string $endpointUrl
* @param array $putData
*
* @return \stdClass
*
* @throws GenericHTTPError
* @throws InvalidCredentials
* @throws MissingEndpoint
* @throws MissingRequiredParameters
*/
public function put($endpointUrl, $putData)
{
return $this->send('PUT', $endpointUrl, $putData);
}
/**
* @param ResponseInterface $responseObj
*
* @return \stdClass
*
* @throws GenericHTTPError
* @throws InvalidCredentials
* @throws MissingEndpoint
* @throws MissingRequiredParameters
*/
public function responseHandler(ResponseInterface $responseObj)
{
$httpResponseCode = $responseObj->getStatusCode();
if ($httpResponseCode === 200) {
$data = (string) $responseObj->getBody();
$jsonResponseData = json_decode($data, false);
$result = new \stdClass();
// return response data as json if possible, raw if not
$result->http_response_body = $data && $jsonResponseData === null ? $data : $jsonResponseData;
} elseif ($httpResponseCode == 400) {
throw new MissingRequiredParameters(ExceptionMessages::EXCEPTION_MISSING_REQUIRED_PARAMETERS.$this->getResponseExceptionMessage($responseObj));
} elseif ($httpResponseCode == 401) {
throw new InvalidCredentials(ExceptionMessages::EXCEPTION_INVALID_CREDENTIALS);
} elseif ($httpResponseCode == 404) {
throw new MissingEndpoint(ExceptionMessages::EXCEPTION_MISSING_ENDPOINT.$this->getResponseExceptionMessage($responseObj));
} else {
throw new GenericHTTPError(ExceptionMessages::EXCEPTION_GENERIC_HTTP_ERROR, $httpResponseCode, $responseObj->getBody());
}
$result->http_response_code = $httpResponseCode;
return $result;
}
/**
* @param ResponseInterface $responseObj
*
* @return string
*/
protected function getResponseExceptionMessage(ResponseInterface $responseObj)
{
$body = (string) $responseObj->getBody();
$response = json_decode($body);
if (json_last_error() == JSON_ERROR_NONE && isset($response->message)) {
return ' '.$response->message;
}
}
/**
* Prepare a file for the postBody.
*
* @param string $fieldName
* @param string|array $filePath
*/
protected function prepareFile($fieldName, $filePath)
{
$filename = null;
// Backward compatibility code
if (is_array($filePath)) {
$filename = $filePath['remoteName'];
$filePath = $filePath['filePath'];
}
// Remove leading @ symbol
if (strpos($filePath, '@') === 0) {
$filePath = substr($filePath, 1);
}
return [
'name' => $fieldName,
'contents' => fopen($filePath, 'r'),
'filename' => $filename,
];
}
/**
*
* @return HttpClient
*/
protected function getHttpClient()
{
if ($this->httpClient === null) {
$this->httpClient = HttpClientDiscovery::find();
}
return $this->httpClient;
}
/**
* @param $uri
*
* @return string
*/
private function getApiUrl($uri)
{
return $this->generateEndpoint($this->apiHost, $this->apiVersion, $this->sslEnabled).$uri;
}
/**
* @param string $apiEndpoint
* @param string $apiVersion
* @param bool $ssl
*
* @return string
*/
private function generateEndpoint($apiEndpoint, $apiVersion, $ssl)
{
if (!$ssl) {
return 'http://'.$apiEndpoint.'/'.$apiVersion.'/';
} else {
return 'https://'.$apiEndpoint.'/'.$apiVersion.'/';
}
}
/**
* @param string $apiVersion
*
* @return RestClient
*/
public function setApiVersion($apiVersion)
{
$this->apiVersion = $apiVersion;
return $this;
}
/**
* @param boolean $sslEnabled
*
* @return RestClient
*/
public function setSslEnabled($sslEnabled)
{
$this->sslEnabled = $sslEnabled;
return $this;
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace Mailgun\Constants;
class Api {
const API_USER = "api";
const SDK_VERSION = "1.7";
const SDK_USER_AGENT = "mailgun-sdk-php";
const RECIPIENT_COUNT_LIMIT = 1000;
const CAMPAIGN_ID_LIMIT = 3;
const TAG_LIMIT = 3;
const DEFAULT_TIME_ZONE = "UTC";
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Mailgun\Constants;
class ExceptionMessages {
const EXCEPTION_INVALID_CREDENTIALS = "Your credentials are incorrect.";
const EXCEPTION_GENERIC_HTTP_ERROR = "An HTTP Error has occurred! Check your network connection and try again.";
const EXCEPTION_MISSING_REQUIRED_PARAMETERS = "The parameters passed to the API were invalid. Check your inputs!";
const EXCEPTION_MISSING_REQUIRED_MIME_PARAMETERS = "The parameters passed to the API were invalid. Check your inputs!";
const EXCEPTION_MISSING_ENDPOINT = "The endpoint you've tried to access does not exist. Check your URL.";
const TOO_MANY_RECIPIENTS = "You've exceeded the maximum recipient count (1,000) on the to field with autosend disabled.";
const INVALID_PARAMETER_NON_ARRAY = "The parameter you've passed in position 2 must be an array.";
const INVALID_PARAMETER_ATTACHMENT = "Attachments must be passed with an \"@\" preceding the file path. Web resources not supported.";
const INVALID_PARAMETER_INLINE = "Inline images must be passed with an \"@\" preceding the file path. Web resources not supported.";
const TOO_MANY_PARAMETERS_CAMPAIGNS = "You've exceeded the maximum (3) campaigns for a single message.";
const TOO_MANY_PARAMETERS_TAGS = "You've exceeded the maximum (3) tags for a single message.";
const TOO_MANY_PARAMETERS_RECIPIENT = "You've exceeded the maximum recipient count (1,000) on the to field with autosend disabled.";
}

View File

@@ -0,0 +1,53 @@
<?PHP
namespace Mailgun\Lists;
use Mailgun\Messages\Exceptions\InvalidParameter;
use Mailgun\Messages\Exceptions\TooManyParameters;
use Mailgun\Messages\Expcetions\InvalidParameterType;
/**
* This class is used for creating a unique hash for
* mailing list subscription double-opt in requests.
*
* @link https://github.com/mailgun/mailgun-php/blob/master/src/Mailgun/Lists/README.md
*/
class OptInHandler{
/**
* @param string $mailingList
* @param string $secretAppId
* @param string $recipientAddress
* @return string
*/
public function generateHash($mailingList, $secretAppId, $recipientAddress){
$innerPayload = array('r' => $recipientAddress, 'l' => $mailingList);
$encodedInnerPayload = base64_encode(json_encode($innerPayload));
$innerHash = hash_hmac("sha1", $encodedInnerPayload, $secretAppId);
$outerPayload = array('h' => $innerHash, 'p' => $encodedInnerPayload);
return urlencode(base64_encode(json_encode($outerPayload)));
}
/**
* @param string $secretAppId
* @param string $uniqueHash
* @return array|bool
*/
public function validateHash($secretAppId, $uniqueHash){
$decodedOuterPayload = json_decode(base64_decode(urldecode($uniqueHash)), true);
$decodedHash = $decodedOuterPayload['h'];
$innerPayload = $decodedOuterPayload['p'];
$decodedInnerPayload = json_decode(base64_decode($innerPayload), true);
$computedInnerHash = hash_hmac("sha1", $innerPayload, $secretAppId);
if($computedInnerHash == $decodedHash){
return array('recipientAddress' => $decodedInnerPayload['r'], 'mailingList' => $decodedInnerPayload['l']);
}
return false;
}
}

View File

@@ -0,0 +1,116 @@
Mailgun - Lists
====================
This is the Mailgun PHP *Lists* utilities.
The below assumes you've already installed the Mailgun PHP SDK in to your project.
If not, go back to the master README for instructions.
There is currently one utility provided.
OptInHandler: Provides methods for authenticating an OptInRequest.
The typical flow for using this utility would be as follows:
**Recipient Requests Subscribe** -> [Validate Recipient Address] -> [Generate Opt In Link] -> [Email Recipient Opt In Link]
**Recipient Clicks Opt In Link** -> [Validate Opt In Link] -> [Subscribe User] -> [Send final confirmation]
The above flow is modeled below.
Usage - Opt-In Handler (Recipient Requests Subscribe)
-----------------------------------------------------
Here's how to use Opt-In Handler to validate Opt-In requests.
```php
# First, instantiate the SDK with your API credentials, domain, and required parameters for example.
$mg = new Mailgun('key-example');
$mgValidate = new Mailgun('pub-key-example');
$domain = 'example.com';
$mailingList = 'youlist@example.com';
$secretPassphrase = 'a_secret_passphrase';
$recipientAddress = 'recipient@example.com';
# Let's validate the customer's email address, using Mailgun's validation endpoint.
$result = $mgValidate->get('address/validate', array('address' => $recipientAddress));
if($result->http_response_body->is_valid == true){
# Next, instantiate an OptInHandler object from the SDK.
$optInHandler = $mg->OptInHandler();
# Next, generate a hash.
$generatedHash = $optInHandler->generateHash($mailingList, $secretPassphrase, $recipientAddress);
# Now, let's send a confirmation to the recipient with our link.
$mg->sendMessage($domain, array('from' => 'bob@example.com',
'to' => $recipientAddress,
'subject' => 'Please Confirm!',
'html' => "<html><body>Hello,<br><br>You have requested to be subscribed
to the mailing list $mailingList. Please <a
href=\"http://yourdomain.com/subscribe.php?hash=$generatedHash\">
confirm</a> your subscription.<br><br>Thank you!</body></html>"));
# Finally, let's add the subscriber to a Mailing List, as unsubscribed, so we can track non-conversions.
$mg->post("lists/$mailingList/members", array('address' => $recipientAddress,
'subscribed' => 'no',
'upsert' => 'yes'));
}
```
Usage - Opt-In Handler (Recipient Clicks Opt In Link)
-----------------------------------------------------
Here's how to use Opt-In Handler to validate an Opt-In Hash.
```php
# First, instantiate the SDK with your API credentials and domain.
$mg = new Mailgun('key-example');
$domain = 'example.com';
# Next, instantiate an OptInHandler object from the SDK.
$optInHandler = $mg->OptInHandler();
# Next, grab the hash.
$inboundHash = $_GET['hash'];
$secretPassphrase = 'a_secret_passphrase';
# Now, validate the captured hash.
$hashValidation = $optInHandler->validateHash($secretPassphrase, $inboundHash);
# Lastly, check to see if we have results, parse, subscribe, and send confirmation.
if($hashValidation){
$validatedList = $hashValidation['mailingList'];
$validatedRecipient = $hashValidation['recipientAddress'];
$mg->put("lists/$validatedList/members/$validatedRecipient",
array('address' => $validatedRecipient,
'subscribed' => 'yes'));
$mg->sendMessage($domain, array('from' => 'bob@example.com',
'to' => $validatedRecipient,
'subject' => 'Confirmation Received!',
'html' => "<html><body>Hello,<br><br>We've successfully subscribed
you to the list, $validatedList!<br><br>Thank you!
</body></html>"));
}
```
A few notes:
1. 'a_secret_passphrase' can be anything. It's used as the *key* in hashing,
since your email address will vary.
2. validateHash() will return an array containing the recipient address and list
address.
3. You should *always* send an email confirmation before and after the
subscription request.
4. WARNING: On $_GET['hash'], you need to sanitize this value to prevent
malicious attempts to inject code.
Available Functions
-----------------------------------------------------
`string generateHash(string $mailingList, string $secretAppId, string $recipientAddress)`
`array validateHash(string $secretAppId, string $uniqueHash)`
More Documentation
------------------
See the official [Mailgun Docs](http://documentation.mailgun.com/api-sending.html)
for more information.

View File

@@ -0,0 +1,185 @@
<?PHP
namespace Mailgun;
use Http\Client\HttpClient;
use Mailgun\Constants\ExceptionMessages;
use Mailgun\Messages\Exceptions;
use Mailgun\Connection\RestClient;
use Mailgun\Messages\BatchMessage;
use Mailgun\Lists\OptInHandler;
use Mailgun\Messages\MessageBuilder;
/**
* This class is the base class for the Mailgun SDK.
* See the official documentation (link below) for usage instructions.
*
* @link https://github.com/mailgun/mailgun-php/blob/master/README.md
*/
class Mailgun{
/**
* @var RestClient
*/
protected $restClient;
/**
* @var null|string
*/
protected $apiKey;
/**
* @param string|null $apiKey
* @param HttpClient $httpClient
* @param string $apiEndpoint
*/
public function __construct(
$apiKey = null,
HttpClient $httpClient = null,
$apiEndpoint = 'api.mailgun.net'
) {
$this->apiKey = $apiKey;
$this->restClient = new RestClient($apiKey, $apiEndpoint, $httpClient);
}
/**
* This function allows the sending of a fully formed message OR a custom
* MIME string. If sending MIME, the string must be passed in to the 3rd
* position of the function call.
*
* @param string $workingDomain
* @param array $postData
* @param array $postFiles
* @throws Exceptions\MissingRequiredMIMEParameters
*/
public function sendMessage($workingDomain, $postData, $postFiles = array()){
if(is_array($postFiles)){
return $this->post("$workingDomain/messages", $postData, $postFiles);
}
else if(is_string($postFiles)){
$tempFile = tempnam(sys_get_temp_dir(), "MG_TMP_MIME");
$fileHandle = fopen($tempFile, "w");
fwrite($fileHandle, $postFiles);
$result = $this->post("$workingDomain/messages.mime", $postData, array("message" => $tempFile));
fclose($fileHandle);
unlink($tempFile);
return $result;
}
else{
throw new Exceptions\MissingRequiredMIMEParameters(ExceptionMessages::EXCEPTION_MISSING_REQUIRED_MIME_PARAMETERS);
}
}
/**
* This function checks the signature in a POST request to see if it is
* authentic.
*
* Pass an array of parameters. If you pass nothing, $_POST will be
* used instead.
*
* If this function returns FALSE, you must not process the request.
* You should reject the request with status code 403 Forbidden.
*
* @param array|null $postData
* @return bool
*/
public function verifyWebhookSignature($postData = NULL) {
if(is_null($postData)) {
$postData = $_POST;
}
$hmac = hash_hmac('sha256', "{$postData["timestamp"]}{$postData["token"]}", $this->apiKey);
$sig = $postData['signature'];
if(function_exists('hash_equals')) {
// hash_equals is constant time, but will not be introduced until PHP 5.6
return hash_equals($hmac, $sig);
}
else {
return ($hmac == $sig);
}
}
/**
* @param string $endpointUrl
* @param array $postData
* @param array $files
* @return \stdClass
*/
public function post($endpointUrl, $postData = array(), $files = array()){
return $this->restClient->post($endpointUrl, $postData, $files);
}
/**
* @param string $endpointUrl
* @param array $queryString
* @return \stdClass
*/
public function get($endpointUrl, $queryString = array()){
return $this->restClient->get($endpointUrl, $queryString);
}
/**
* @param string $endpointUrl
* @return \stdClass
*/
public function delete($endpointUrl){
return $this->restClient->delete($endpointUrl);
}
/**
* @param string $endpointUrl
* @param array $putData
* @return \stdClass
*/
public function put($endpointUrl, $putData){
return $this->restClient->put($endpointUrl, $putData);
}
/**
* @param string $apiVersion
*
* @return Mailgun
*/
public function setApiVersion($apiVersion)
{
$this->restClient->setApiVersion($apiVersion);
return $this;
}
/**
* @param boolean $sslEnabled
*
* @return Mailgun
*/
public function setSslEnabled($sslEnabled)
{
$this->restClient->setSslEnabled($sslEnabled);
return $this;
}
/**
* @return MessageBuilder
*/
public function MessageBuilder(){
return new MessageBuilder();
}
/**
* @return OptInHandler
*/
public function OptInHandler(){
return new OptInHandler();
}
/**
* @param string $workingDomain
* @param bool $autoSend
* @return BatchMessage
*/
public function BatchMessage($workingDomain, $autoSend = true){
return new BatchMessage($this->restClient, $workingDomain, $autoSend);
}
}

View File

@@ -0,0 +1,141 @@
<?PHP
namespace Mailgun\Messages;
use Mailgun\Constants\Api;
use Mailgun\Constants\ExceptionMessages;
use Mailgun\Messages\Exceptions\TooManyParameters;
use Mailgun\Messages\Exceptions\MissingRequiredMIMEParameters;
/**
* This class is used for batch sending. See the official documentation (link below)
* for usage instructions.
*
* @link https://github.com/mailgun/mailgun-php/blob/master/src/Mailgun/Messages/README.md
*/
class BatchMessage extends MessageBuilder{
/**
* @var array
*/
private $batchRecipientAttributes;
/**
* @var boolean
*/
private $autoSend;
/**
* @var \Mailgun\Connection\RestClient
*/
private $restClient;
/**
* @var string
*/
private $workingDomain;
/**
* @var array
*/
private $messageIds = array();
/**
* @param \Mailgun\Connection\RestClient $restClient
* @param string $workingDomain
* @param boolean $autoSend
*/
public function __construct($restClient, $workingDomain, $autoSend){
$this->batchRecipientAttributes = array();
$this->autoSend = $autoSend;
$this->restClient = $restClient;
$this->workingDomain = $workingDomain;
$this->endpointUrl = $workingDomain . "/messages";
}
/**
* @param string $headerName
* @param string $address
* @param array $variables
* @throws MissingRequiredMIMEParameters
* @throws TooManyParameters
*/
protected function addRecipient($headerName, $address, $variables){
if(array_key_exists($headerName, $this->counters['recipients'])){
if($this->counters['recipients'][$headerName] == Api::RECIPIENT_COUNT_LIMIT){
if($this->autoSend == false){
throw new TooManyParameters(ExceptionMessages::TOO_MANY_RECIPIENTS);
}
$this->sendMessage();
}
}
$compiledAddress = $this->parseAddress($address, $variables);
if(isset($this->message[$headerName])){
array_push($this->message[$headerName], $compiledAddress);
}
elseif($headerName == "h:reply-to"){
$this->message[$headerName] = $compiledAddress;
}
else{
$this->message[$headerName] = array($compiledAddress);
}
if(array_key_exists($headerName, $this->counters['recipients'])){
$this->counters['recipients'][$headerName] += 1;
if(!array_key_exists("id", $variables)){
$variables['id'] = $this->counters['recipients'][$headerName];
}
}
$this->batchRecipientAttributes["$address"] = $variables;
}
/**
* @param array $message
* @param array $files
* @throws MissingRequiredMIMEParameters
*/
public function sendMessage($message = array(), $files = array()){
if(count($message) < 1){
$message = $this->message;
$files = $this->files;
}
if(!array_key_exists("from", $message)){
throw new MissingRequiredMIMEParameters(ExceptionMessages::EXCEPTION_MISSING_REQUIRED_MIME_PARAMETERS);
}
elseif(!array_key_exists("to", $message)){
throw new MissingRequiredMIMEParameters(ExceptionMessages::EXCEPTION_MISSING_REQUIRED_MIME_PARAMETERS);
}
elseif(!array_key_exists("subject", $message)){
throw new MissingRequiredMIMEParameters(ExceptionMessages::EXCEPTION_MISSING_REQUIRED_MIME_PARAMETERS);
}
elseif((!array_key_exists("text", $message) && !array_key_exists("html", $message))){
throw new MissingRequiredMIMEParameters(ExceptionMessages::EXCEPTION_MISSING_REQUIRED_MIME_PARAMETERS);
}
else{
$message["recipient-variables"] = json_encode($this->batchRecipientAttributes);
$response = $this->restClient->post($this->endpointUrl, $message, $files);
$this->batchRecipientAttributes = array();
$this->counters['recipients']['to'] = 0;
$this->counters['recipients']['cc'] = 0;
$this->counters['recipients']['bcc'] = 0;
unset($this->message["to"]);
array_push($this->messageIds, $response->http_response_body->id);
}
}
/**
* @throws MissingRequiredMIMEParameters
*/
public function finalize(){
$this->sendMessage();
}
/**
* @return string[]
*/
public function getMessageIds(){
return $this->messageIds;
}
}

View File

@@ -0,0 +1,4 @@
<?php
namespace Mailgun\Messages\Exceptions;
class InvalidParameter extends \Exception{}

View File

@@ -0,0 +1,4 @@
<?php
namespace Mailgun\Messages\Exceptions;
class InvalidParameterType extends \Exception{}

View File

@@ -0,0 +1,4 @@
<?php
namespace Mailgun\Messages\Exceptions;
class MissingRequiredMIMEParameters extends \Exception{}

View File

@@ -0,0 +1,4 @@
<?php
namespace Mailgun\Messages\Exceptions;
class TooManyParameters extends \Exception{}

View File

@@ -0,0 +1,482 @@
<?PHP
namespace Mailgun\Messages;
use Mailgun\Constants\Api;
use Mailgun\Constants\ExceptionMessages;
use Mailgun\Messages\Exceptions\InvalidParameter;
use Mailgun\Messages\Exceptions\TooManyParameters;
/**
* This class is used for composing a properly formed
* message object. Dealing with arrays can be cumbersome,
* this class makes the process easier. See the official
* documentation (link below) for usage instructions.
*
* @link https://github.com/mailgun/mailgun-php/blob/master/src/Mailgun/Messages/README.md
*/
class MessageBuilder
{
/**
* @var array
*/
protected $message = array();
/**
* @var array
*/
protected $variables = array();
/**
* @var array
*/
protected $files = array();
/**
* @var array
*/
protected $counters = array(
'recipients' => array(
'to' => 0,
'cc' => 0,
'bcc' => 0
),
'attributes' => array(
'attachment' => 0,
'campaign_id' => 0,
'custom_option' => 0,
'tag' => 0
)
);
/**
* @param array $params
* @param string $key
* @param mixed $default
* @return mixed
*/
protected function safeGet($params, $key, $default)
{
if (array_key_exists($key, $params)) {
return $params[$key];
}
return $default;
}
/**
* @param array $params
* @return mixed|string
*/
protected function getFullName($params)
{
if (array_key_exists("first", $params)) {
$first = $this->safeGet($params, "first", "");
$last = $this->safeGet($params, "last", "");
return trim("$first $last");
}
return $this->safeGet($params, "full_name", "");
}
/**
* @param string $address
* @param array $variables
* @return string
*/
protected function parseAddress($address, $variables)
{
if (!is_array($variables)) {
return $address;
}
$fullName = $this->getFullName($variables);
if ($fullName != null) {
return "'$fullName' <$address>";
}
return $address;
}
/**
* @param string $headerName
* @param string $address
* @param array $variables
*/
protected function addRecipient($headerName, $address, $variables)
{
$compiledAddress = $this->parseAddress($address, $variables);
if (isset($this->message[$headerName])) {
array_push($this->message[$headerName], $compiledAddress);
} elseif ($headerName == "h:reply-to") {
$this->message[$headerName] = $compiledAddress;
} else {
$this->message[$headerName] = array($compiledAddress);
}
if (array_key_exists($headerName, $this->counters['recipients'])) {
$this->counters['recipients'][$headerName] += 1;
}
}
/**
* @param string $address
* @param array|null $variables
* @return mixed
* @throws TooManyParameters
*/
public function addToRecipient($address, $variables = null)
{
if ($this->counters['recipients']['to'] > Api::RECIPIENT_COUNT_LIMIT) {
throw new TooManyParameters(ExceptionMessages::TOO_MANY_PARAMETERS_RECIPIENT);
}
$this->addRecipient("to", $address, $variables);
return end($this->message['to']);
}
/**
* @param string $address
* @param array|null $variables
* @return mixed
* @throws TooManyParameters
*/
public function addCcRecipient($address, $variables = null)
{
if ($this->counters['recipients']['cc'] > Api::RECIPIENT_COUNT_LIMIT) {
throw new TooManyParameters(ExceptionMessages::TOO_MANY_PARAMETERS_RECIPIENT);
}
$this->addRecipient("cc", $address, $variables);
return end($this->message['cc']);
}
/**
* @param string $address
* @param array|null $variables
* @return mixed
* @throws TooManyParameters
*/
public function addBccRecipient($address, $variables = null)
{
if ($this->counters['recipients']['bcc'] > Api::RECIPIENT_COUNT_LIMIT) {
throw new TooManyParameters(ExceptionMessages::TOO_MANY_PARAMETERS_RECIPIENT);
}
$this->addRecipient("bcc", $address, $variables);
return end($this->message['bcc']);
}
/**
* @param string $address
* @param array|null $variables
* @return mixed
*/
public function setFromAddress($address, $variables = null)
{
$this->addRecipient("from", $address, $variables);
return $this->message['from'];
}
/**
* @param string $address
* @param array|null $variables
* @return mixed
*/
public function setReplyToAddress($address, $variables = null)
{
$this->addRecipient("h:reply-to", $address, $variables);
return $this->message['h:reply-to'];
}
/**
* @param string $subject
* @return mixed
*/
public function setSubject($subject = "")
{
if ($subject == null || $subject == "") {
$subject = " ";
}
$this->message['subject'] = $subject;
return $this->message['subject'];
}
/**
* @param string $headerName
* @param mixed $headerData
* @return mixed
*/
public function addCustomHeader($headerName, $headerData)
{
if (!preg_match("/^h:/i", $headerName)) {
$headerName = "h:" . $headerName;
}
$this->message[$headerName] = array($headerData);
return $this->message[$headerName];
}
/**
* @param string $textBody
* @return string
*/
public function setTextBody($textBody)
{
if ($textBody == null || $textBody == "") {
$textBody = " ";
}
$this->message['text'] = $textBody;
return $this->message['text'];
}
/**
* @param string $htmlBody
* @return string
*/
public function setHtmlBody($htmlBody)
{
if ($htmlBody == null || $htmlBody == "") {
$htmlBody = " ";
}
$this->message['html'] = $htmlBody;
return $this->message['html'];
}
/**
* @param string $attachmentPath
* @param string|null $attachmentName
* @return bool
*/
public function addAttachment($attachmentPath, $attachmentName = null)
{
if (isset($this->files["attachment"])) {
$attachment = array(
'filePath' => $attachmentPath,
'remoteName' => $attachmentName
);
array_push($this->files["attachment"], $attachment);
} else {
$this->files["attachment"] = array(
array(
'filePath' => $attachmentPath,
'remoteName' => $attachmentName
)
);
}
return true;
}
/**
* @param string $inlineImagePath
* @param string|null $inlineImageName
* @throws InvalidParameter
*/
public function addInlineImage($inlineImagePath, $inlineImageName = null)
{
if (preg_match("/^@/", $inlineImagePath)) {
if (isset($this->files['inline'])) {
$inlineAttachment = array(
'filePath' => $inlineImagePath,
'remoteName' => $inlineImageName
);
array_push($this->files['inline'], $inlineAttachment);
} else {
$this->files['inline'] = array(
array(
'filePath' => $inlineImagePath,
'remoteName' => $inlineImageName
)
);
}
return true;
} else {
throw new InvalidParameter(ExceptionMessages::INVALID_PARAMETER_INLINE);
}
}
/**
* @param boolean $testMode
* @return string
*/
public function setTestMode($testMode)
{
if (filter_var($testMode, FILTER_VALIDATE_BOOLEAN)) {
$testMode = "yes";
} else {
$testMode = "no";
}
$this->message['o:testmode'] = $testMode;
return $this->message['o:testmode'];
}
/**
* @param string|int $campaignId
* @return string|int
* @throws TooManyParameters
*/
public function addCampaignId($campaignId)
{
if ($this->counters['attributes']['campaign_id'] < Api::CAMPAIGN_ID_LIMIT) {
if (isset($this->message['o:campaign'])) {
array_push($this->message['o:campaign'], $campaignId);
} else {
$this->message['o:campaign'] = array($campaignId);
}
$this->counters['attributes']['campaign_id'] += 1;
return $this->message['o:campaign'];
} else {
throw new TooManyParameters(ExceptionMessages::TOO_MANY_PARAMETERS_CAMPAIGNS);
}
}
/**
* @param string $tag
* @throws TooManyParameters
*/
public function addTag($tag)
{
if ($this->counters['attributes']['tag'] < Api::TAG_LIMIT) {
if (isset($this->message['o:tag'])) {
array_push($this->message['o:tag'], $tag);
} else {
$this->message['o:tag'] = array($tag);
}
$this->counters['attributes']['tag'] += 1;
return $this->message['o:tag'];
} else {
throw new TooManyParameters(ExceptionMessages::TOO_MANY_PARAMETERS_TAGS);
}
}
/**
* @param boolean $enabled
* @return mixed
*/
public function setDkim($enabled)
{
if (filter_var($enabled, FILTER_VALIDATE_BOOLEAN)) {
$enabled = "yes";
} else {
$enabled = "no";
}
$this->message["o:dkim"] = $enabled;
return $this->message["o:dkim"];
}
/**
* @param boolean $enabled
* @return string
*/
public function setOpenTracking($enabled)
{
if (filter_var($enabled, FILTER_VALIDATE_BOOLEAN)) {
$enabled = "yes";
} else {
$enabled = "no";
}
$this->message['o:tracking-opens'] = $enabled;
return $this->message['o:tracking-opens'];
}
/**
* @param boolean $enabled
* @return string
*/
public function setClickTracking($enabled)
{
if (filter_var($enabled, FILTER_VALIDATE_BOOLEAN)) {
$enabled = "yes";
} elseif ($enabled == "html") {
$enabled = "html";
} else {
$enabled = "no";
}
$this->message['o:tracking-clicks'] = $enabled;
return $this->message['o:tracking-clicks'];
}
/**
* @param string $timeDate
* @param string|null $timeZone
* @return string
*/
public function setDeliveryTime($timeDate, $timeZone = null)
{
if (isset($timeZone)) {
$timeZoneObj = new \DateTimeZone("$timeZone");
} else {
$timeZoneObj = new \DateTimeZone(Api::DEFAULT_TIME_ZONE);
}
$dateTimeObj = new \DateTime($timeDate, $timeZoneObj);
$formattedTimeDate = $dateTimeObj->format(\DateTime::RFC2822);
$this->message['o:deliverytime'] = $formattedTimeDate;
return $this->message['o:deliverytime'];
}
/**
* @param string $customName
* @param mixed $data
*/
public function addCustomData($customName, $data)
{
$this->message['v:' . $customName] = json_encode($data);
}
/**
* @param string $parameterName
* @param mixed $data
* @return mixed
*/
public function addCustomParameter($parameterName, $data)
{
if (isset($this->message[$parameterName])) {
array_push($this->message[$parameterName], $data);
return $this->message[$parameterName];
} else {
$this->message[$parameterName] = array($data);
return $this->message[$parameterName];
}
}
/**
* @param array $message
*/
public function setMessage($message)
{
$this->message = $message;
}
/**
* @return array
*/
public function getMessage()
{
return $this->message;
}
/**
* @return array
*/
public function getFiles()
{
return $this->files;
}
}

View File

@@ -0,0 +1,138 @@
Mailgun - Messages
====================
This is the Mailgun PHP *Message* utilities.
The below assumes you've already installed the Mailgun PHP SDK in to your
project. If not, go back to the master README for instructions.
There are two utilities included, Message Builder and Batch Message.
Message Builder: Allows you to build a message object by calling methods for
each MIME attribute.
Batch Message: Inherits Message Builder and allows you to iterate through
recipients from a list. Messages will fire after the 1,000th recipient has been
added.
Usage - Message Builder
-----------------------
Here's how to use Message Builder to build your Message.
```php
# First, instantiate the SDK with your API credentials and define your domain.
$mg = new Mailgun("key-example");
$domain = "example.com";
# Next, instantiate a Message Builder object from the SDK.
$messageBldr = $mg->MessageBuilder();
# Define the from address.
$messageBldr->setFromAddress("me@example.com", array("first"=>"PHP", "last" => "SDK"));
# Define a to recipient.
$messageBldr->addToRecipient("john.doe@example.com", array("first" => "John", "last" => "Doe"));
# Define a cc recipient.
$messageBldr->addCcRecipient("sally.doe@example.com", array("first" => "Sally", "last" => "Doe"));
# Define the subject.
$messageBldr->setSubject("A message from the PHP SDK using Message Builder!");
# Define the body of the message.
$messageBldr->setTextBody("This is the text body of the message!");
# Other Optional Parameters.
$messageBldr->addCampaignId("My-Awesome-Campaign");
$messageBldr->addCustomHeader("Customer-Id", "12345");
$messageBldr->addAttachment("@/tron.jpg");
$messageBldr->setDeliveryTime("tomorrow 8:00AM", "PST");
$messageBldr->setClickTracking(true);
# Finally, send the message.
$mg->post("{$domain}/messages", $messageBldr->getMessage(), $messageBldr->getFiles());
```
Available Functions
-----------------------------------------------------
`string addToRecipient(string $address, array $attributes)`
`string addCcRecipient(string $address, array $attributes)`
`string addBccRecipient(string $address, array $attributes)`
`string setFromAddress(string $address, array $attributes)`
`string setSubject(string $subject)`
`string setTextBody(string $textBody)`
`string setHtmlBody(string $htmlBody)`
`bool addAttachment(string $attachmentPath)`
`bool addInlineImage(string $inlineImagePath)`
`string setTestMode(bool $testMode)`
`string addCampaignId(string $campaignId)`
`string setDkim(bool $enabled)`
`string setOpenTracking($enabled)`
`string setClickTracking($enabled)`
`string setDeliveryTime(string $timeDate, string $timeZone)`
`string addCustomData(string $optionName, string $data)`
`string addCustomParameter(string $parameterName, string $data)`
`array getMessage()`
`array getFiles()`
Usage - Batch Message
---------------------
Here's how to use Batch Message to easily handle batch sending jobs.
```php
# First, instantiate the SDK with your API credentials and define your domain.
$mg = new Mailgun("key-example");
$domain = "example.com";
# Next, instantiate a Message Builder object from the SDK, pass in your sending
domain.
$batchMsg = $mg->BatchMessage($domain);
# Define the from address.
$batchMsg->setFromAddress("me@example.com", array("first"=>"PHP", "last" => "SDK"));
# Define the subject.
$batchMsg->setSubject("A Batch Message from the PHP SDK!");
# Define the body of the message.
$batchMsg->setTextBody("This is the text body of the message!");
# Next, let's add a few recipients to the batch job.
$batchMsg->addToRecipient("john.doe@example.com", array("first" => "John", "last" => "Doe"));
$batchMsg->addToRecipient("sally.doe@example.com", array("first" => "Sally", "last" => "Doe"));
$batchMsg->addToRecipient("mike.jones@example.com", array("first" => "Mike", "last" => "Jones"));
...
// After 1,000 recipeints, Batch Message will automatically post your message to
the messages endpoint.
// Call finalize() to send any remaining recipients still in the buffer.
$batchMsg->finalize();
```
Available Functions (Inherits all Batch Message and Messages Functions)
-----------------------------------------------------------------------
`addToRecipient(string $address, string $attributes)`
`sendMessage(array $message, array $files)`
`array finalize()`
More Documentation
------------------
See the official [Mailgun Docs](http://documentation.mailgun.com/api-sending.html)
for more information.