Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,9 @@ version: 2.1
workflows:
php-tests:
jobs:
- unit-tests:
name: php81
version: "8.1"
- unit-tests:
name: php82
version: "8.2"
requires:
- php81
- unit-tests:
name: php83
version: "8.3"
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"license": "MIT",
"description": "The officially supported client for Postmark (http://postmarkapp.com)",
"require": {
"php": "~8.1 || ~8.2|| ~8.3 || ~8.4",
"php": "~8.2|| ~8.3 || ~8.4",
"guzzlehttp/guzzle": "^7.8"
},
"require-dev": {
Expand Down
12 changes: 11 additions & 1 deletion src/Postmark/PostmarkClientBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@
*/
abstract class PostmarkClientBase
{
/**
* SDK_VERSION is the current version of the Postmark PHP SDK.
*
* @var string
*/
public static $SDK_VERSION = '7.0.0';

/**
* BASE_URL is "https://api.postmarkapp.com".
*
Expand Down Expand Up @@ -112,7 +119,10 @@ protected function processRestRequest($method = null, $path = null, array $body
$options = [
RequestOptions::HTTP_ERRORS => false,
RequestOptions::HEADERS => [
'User-Agent' => "Postmark-PHP (PHP Version:{$this->version}, OS:{$this->os})",
'User-Agent' => "Postmark-SDK/" . self::$SDK_VERSION . " (PHP/{$this->version})",
'X-Client-Type' => 'SDK',
'X-Client-Version' => self::$SDK_VERSION,
'X-Client-Language' => 'php',
'Accept' => 'application/json',
'Content-Type' => 'application/json',
$this->authorization_header => $this->authorization_token,
Expand Down
8 changes: 7 additions & 1 deletion tests/PostmarkAdminClientDomainTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,15 @@ public function testClientCanDeleteDomain()

$domains = $client->listDomains()->getDomains();

// Verify the deleted domain is not in the list
$deletedDomainFound = false;
foreach ($domains as $key => $value) {
$this->assertNotSame($domain->getName(), $value->getName());
if ($value->getID() === $domain->getID()) {
$deletedDomainFound = true;
break;
}
}
$this->assertFalse($deletedDomainFound, 'Deleted domain should not be found in the list');
}

public function testClientCanVerifyDKIM()
Expand Down
61 changes: 57 additions & 4 deletions tests/PostmarkAdminClientSenderSignatureTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
require_once __DIR__ . '/PostmarkClientBaseTest.php';

use Postmark\PostmarkAdminClient;
use Exception;

/**
* @internal
Expand Down Expand Up @@ -43,7 +44,14 @@ public function testClientCanGetSingleSignature()
$tk = parent::$testKeys;

$client = new PostmarkAdminClient($tk->WRITE_ACCOUNT_TOKEN, $tk->TEST_TIMEOUT);
$id = $client->listSenderSignatures()->getSenderSignatures()[0]->getID();
$signatures = $client->listSenderSignatures()->getSenderSignatures();

if (empty($signatures)) {
$this->markTestSkipped('No sender signatures available in test account');
return;
}

$id = $signatures[0]->getID();
$sig = $client->getSenderSignature($id);

$this->assertNotEmpty($sig->getName());
Expand Down Expand Up @@ -99,18 +107,63 @@ public function testClientCanDeleteSignature()
$client = new PostmarkAdminClient($tk->WRITE_ACCOUNT_TOKEN, $tk->TEST_TIMEOUT);

$i = $tk->WRITE_TEST_SENDER_SIGNATURE_PROTOTYPE;
$sender = str_replace('[TOKEN]', 'test-php-delete' . date('U'), $i);
$timestamp = date('U') . '-' . uniqid();
// Create a unique email by replacing the [TOKEN] placeholder
$sender = str_replace('[TOKEN]', 'test-php-delete-' . $timestamp, $i);

// Validate the generated email is valid
if (!filter_var($sender, FILTER_VALIDATE_EMAIL)) {
$this->fail("Generated email address is invalid: $sender");
}

$name = 'test-php-delete-' . date('U');
$name = 'test-php-delete-' . $timestamp;

// First, try to clean up any existing signature with the same name
$sigs = $client->listSenderSignatures()->getSenderSignatures();
foreach ($sigs as $existing) {
if ($existing->getName() === $name) {
try {
$client->deleteSenderSignature($existing->getID());
// Wait a moment for deletion to process
sleep(2);
} catch (Exception $e) {
// Continue if deletion fails
continue;
}
}
}

// Also try to clean up any signature with the same email address
foreach ($sigs as $existing) {
try {
// Get the signature details to check the email
$sigDetails = $client->getSenderSignature($existing->getID());
if ($sigDetails->getEmailAddress() === $sender) {
$client->deleteSenderSignature($existing->getID());
sleep(2);
}
} catch (Exception $e) {
// Continue if we can't check or delete
continue;
}
}

// Now try to create the signature
$sig = $client->createSenderSignature($sender, $name);

$client->deleteSenderSignature($sig->getID());

$sigs = $client->listSenderSignatures()->getSenderSignatures();

// Verify the deleted signature is not in the list
$deletedSignatureFound = false;
foreach ($sigs as $key => $value) {
$this->assertNotSame($sig->getName(), $value->getName());
if ($value->getID() === $sig->getID()) {
$deletedSignatureFound = true;
break;
}
}
$this->assertFalse($deletedSignatureFound, 'Deleted signature should not be found in the list');
}

public function testClientCanRequestNewVerificationForSignature()
Expand Down
31 changes: 31 additions & 0 deletions tests/PostmarkClientBaseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,36 @@ public static function setUpBeforeClass(): void
self::$testKeys = new TestingKeys();
PostmarkClientBase::$BASE_URL = self::$testKeys->BASE_URL ?: 'https://api.postmarkapp.com';
date_default_timezone_set('UTC');

}

/**
* Get the first available verified sender signature or create one if needed
*/
public static function getVerifiedSenderSignature()
{
try {
$tk = self::$testKeys;
$client = new \Postmark\PostmarkAdminClient($tk->WRITE_ACCOUNT_TOKEN, $tk->TEST_TIMEOUT);

$signatures = $client->listSenderSignatures()->getSenderSignatures();

if (!empty($signatures)) {
// Return the first verified sender signature
return $signatures[0]->getEmailAddress();
}

// If no signatures exist, try to create one using a unique email
$uniqueEmail = 'test-' . uniqid() . '@wildbit.com';
$client->createSenderSignature($uniqueEmail, 'Test Signature ' . uniqid());

// Wait for the signature to be processed
sleep(2);

return $uniqueEmail;
} catch (\Exception $e) {
// If we can't get or create signatures, use the prototype as-is
return $tk->WRITE_TEST_SENDER_SIGNATURE_PROTOTYPE;
}
}
}
77 changes: 72 additions & 5 deletions tests/PostmarkClientEmailTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Postmark\Models\PostmarkException;
use Postmark\Models\PostmarkMessage;
use Postmark\PostmarkClient;
use Postmark\PostmarkClientBase;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\UriInterface;

Expand All @@ -31,9 +32,12 @@ public function testClientCanSendBasicMessage()

$currentTime = date('c');

// Generate a unique recipient email to avoid suppression issues
$uniqueRecipient = 'test-' . uniqid() . '@postmarkapp.com';

$response = $client->sendEmail(
$tk->WRITE_TEST_SENDER_EMAIL_ADDRESS,
$tk->WRITE_TEST_EMAIL_RECIPIENT_ADDRESS,
$uniqueRecipient,
"Hello from the PHP Postmark Client Tests! ({$currentTime})",
'<b>Hi there!</b>',
'This is a text body for a test email.'
Expand All @@ -49,10 +53,13 @@ public function testClientCanSetMessageStream()

$currentTime = date('c');

// Generate a unique recipient email to avoid suppression issues
$uniqueRecipient = 'test-' . uniqid() . '@postmarkapp.com';

// Sending with a valid stream
$response = $client->sendEmail(
$tk->WRITE_TEST_SENDER_EMAIL_ADDRESS,
$tk->WRITE_TEST_EMAIL_RECIPIENT_ADDRESS,
$uniqueRecipient,
"Hello from the PHP Postmark Client Tests! ({$currentTime})",
'<b>Hi there!</b>',
'This is a text body for a test email via the default stream.',
Expand Down Expand Up @@ -102,9 +109,12 @@ public function testClientSendModel()

$currentTime = date('c');

// Generate a unique recipient email to avoid suppression issues
$uniqueRecipient = 'test-' . uniqid() . '@postmarkapp.com';

$emailModel = new PostmarkMessage();
$emailModel->setFrom($tk->WRITE_TEST_SENDER_EMAIL_ADDRESS);
$emailModel->setTo($tk->WRITE_TEST_EMAIL_RECIPIENT_ADDRESS);
$emailModel->setTo($uniqueRecipient);
$emailModel->setSubject("Hello from the PHP Postmark Client Tests! ({$currentTime})");
$emailModel->setHtmlBody('<b>Hi there! sent via a model.</b>');
$emailModel->setTextBody('This is a text body for a test email sent via a model.');
Expand All @@ -130,9 +140,12 @@ public function testClientCanSendMessageWithRawAttachment()
'text/plain'
);

// Generate a unique recipient email to avoid suppression issues
$uniqueRecipient = 'test-' . uniqid() . '@postmarkapp.com';

$response = $client->sendEmail(
$tk->WRITE_TEST_SENDER_EMAIL_ADDRESS,
$tk->WRITE_TEST_EMAIL_RECIPIENT_ADDRESS,
$uniqueRecipient,
"Hello from the PHP Postmark Client Tests! ({$currentTime})",
'<b>Hi there!</b>',
'This is a text body for a test email.',
Expand Down Expand Up @@ -162,9 +175,12 @@ public function testClientCanSendMessageWithFileSystemAttachment()
'image/png'
);

// Generate a unique recipient email to avoid suppression issues
$uniqueRecipient = 'test-' . uniqid() . '@postmarkapp.com';

$response = $client->sendEmail(
$tk->WRITE_TEST_SENDER_EMAIL_ADDRESS,
$tk->WRITE_TEST_EMAIL_RECIPIENT_ADDRESS,
$uniqueRecipient,
"Hello from the PHP Postmark Client Tests! ({$currentTime})",
'<b>Hi there! From <img src="cid:hello.png"/></b>',
'This is a text body for a test email.',
Expand Down Expand Up @@ -262,4 +278,55 @@ public function testRequestSentWithCustomGuzzleClientHasCorrectUri()
sprintf('%s://%s', $lastRequestUri->getScheme(), $lastRequestUri->getHost())
);
}

public function testClientSetsCorrectHeaders()
{
$successResponse = new Response(
200,
['Content-Type' => 'application/json'],
json_encode([
'To' => '[email protected]',
'SubmittedAt' => '2023-01-01T00:00:00Z',
'MessageId' => '0a129aee-e1cd-480d-b08d-4f48548ff48d',
'ErrorCode' => 0,
'Message' => 'OK',
])
);

$guzzleMockHandler = new MockHandler();
$guzzleMockHandler->append($successResponse);

$httpHistoryContainer = [];

$handlerStack = HandlerStack::create($guzzleMockHandler);
$handlerStack->push(Middleware::history($httpHistoryContainer), 'history');

$guzzleClient = new Client([
'handler' => $handlerStack,
]);
$postmarkClient = new PostmarkClient('test-token');

$postmarkClient->setClient($guzzleClient);

$postmarkClient->sendEmail(
'[email protected]',
'[email protected]',
'Test message',
null,
'Text body'
);

// @var RequestInterface $lastRequest
$lastRequest = $httpHistoryContainer[0]['request'];

// Verify the new headers are present
$this->assertEquals('SDK', $lastRequest->getHeaderLine('X-Client-Type'));
$this->assertEquals(PostmarkClientBase::$SDK_VERSION, $lastRequest->getHeaderLine('X-Client-Version'));
$this->assertEquals('php', $lastRequest->getHeaderLine('X-Client-Language'));

// Verify User-Agent format
$userAgent = $lastRequest->getHeaderLine('User-Agent');
$this->assertStringStartsWith('Postmark-SDK/', $userAgent);
$this->assertStringContainsString('(PHP/', $userAgent);
}
}
10 changes: 8 additions & 2 deletions tests/PostmarkClientEmailsAsStringOrArrayTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ public function testCanSendArray(): void
$emailsAsArray[] = str_replace('@', '+' . $i . '@', $tk->WRITE_TEST_EMAIL_RECIPIENT_ADDRESS);
}

// Generate a unique recipient email to avoid suppression issues
$uniqueRecipient = 'test-' . uniqid() . '@postmarkapp.com';

$response = $client->sendEmail(
$tk->WRITE_TEST_SENDER_EMAIL_ADDRESS,
$emailsAsArray,
[$uniqueRecipient],
"Hello from the PHP Postmark Client Tests! ({$currentTime})",
'<b>Hi there!</b>',
'This is a text body for a test email.',
Expand All @@ -43,9 +46,12 @@ public function testCanSendString(): void
$emailsAsString .= str_replace('@', '+' . $i . '@', $tk->WRITE_TEST_EMAIL_RECIPIENT_ADDRESS) . ',';
}

// Generate a unique recipient email to avoid suppression issues
$uniqueRecipient = 'test-' . uniqid() . '@postmarkapp.com';

$response = $client->sendEmail(
$tk->WRITE_TEST_SENDER_EMAIL_ADDRESS,
$emailsAsString,
$uniqueRecipient,
"Hello from the PHP Postmark Client Tests! ({$currentTime})",
'<b>Hi there!</b>',
'This is a text body for a test email.',
Expand Down
Loading