PHP SDK
PHP 8.1+
Composer
Send emails with PHP using the official Laneful PHP SDK. Built for modern PHP applications with comprehensive features and type safety.
Full Feature Support
Templates, attachments, tracking, webhooks
Type Safe
Built-in validation & error handling
Modern PHP
PHP 8.1+ with named parameters
On this page
Prerequisites
To get the most out of this guide, you'll need:
- • PHP 8.1 or higher
- • Composer 2.0+
- • A Laneful account with API key
- • Verified domain for sending emails
Installation
Composer
Add the following dependency to your composer.json
:
composer require lanefulhq/laneful-php
Quick Start
Send your first email in minutes:
Send Simple Text Email
<?php require_once 'vendor/autoload.php'; use Laneful\LanefulClient; use Laneful\Models\Email; use Laneful\Models\Address; use Laneful\Exceptions\*; // Create client $client = new LanefulClient( baseUrl: 'https://your-endpoint.send.laneful.net', authToken: 'your-auth-token' ); // Create email $email = new Email( from: new Address('sender@example.com', 'Your Name'), to: [new Address('recipient@example.com', 'Recipient Name')], subject: 'Hello from Laneful!', textContent: 'This is a simple test email sent using the Laneful PHP SDK.' ); // Send email try { $response = $client->sendEmail($email); echo "✓ Email sent successfully!\n"; echo "Response: " . json_encode($response) . "\n"; } catch (ValidationException $e) { echo "✗ Validation error: " . $e->getMessage() . "\n"; } catch (ApiException $e) { echo "✗ API error: " . $e->getMessage() . "\n"; echo "Status code: " . $e->getCode() . "\n"; } catch (HttpException $e) { echo "✗ HTTP error: " . $e->getMessage() . "\n"; } catch (Exception $e) { echo "✗ Unexpected error: " . $e->getMessage() . "\n"; }
Examples
Common use cases and patterns:
HTML Email with Tracking
use Laneful\Models\TrackingSettings; // Create tracking settings $tracking = new TrackingSettings(opens: true, clicks: true, unsubscribes: true); $email = new Email( from: new Address('sender@example.com', 'Your Name'), to: [new Address('recipient@example.com', 'Recipient Name')], subject: 'HTML Email with Tracking', htmlContent: '<h1>Welcome!</h1><p>This is an <strong>HTML email</strong> with tracking enabled.</p>', textContent: 'Welcome! This is an HTML email with tracking enabled.', tracking: $tracking, tag: 'welcome-email' ); $response = $client->sendEmail($email);
Template Email
$email = new Email( from: new Address('sender@example.com'), to: [new Address('user@example.com')], subject: 'Welcome {{name}}!', templateId: 'welcome-template', templateData: [ 'name' => 'John Doe', 'company' => 'Acme Corporation', 'activation_link' => 'https://example.com/activate' ], tracking: new TrackingSettings(opens: true, clicks: true) ); $response = $client->sendEmail($email);
Email with Attachments
use Laneful\Models\Attachment; // Create attachment from file $attachment = Attachment::fromFile('/path/to/document.pdf'); $email = new Email( from: new Address('sender@example.com'), to: [new Address('user@example.com')], subject: 'Document Attached', textContent: 'Please find the document attached.', attachments: [$attachment], tracking: new TrackingSettings(opens: true, clicks: true) ); $response = $client->sendEmail($email);
Multiple Recipients with Reply-To
$email = new Email( from: new Address('sender@example.com', 'Your Name'), to: [ new Address('user1@example.com', 'User One'), new Address('user2@example.com', 'User Two') ], cc: [new Address('cc@example.com', 'CC Recipient')], bcc: [new Address('bcc@example.com', 'BCC Recipient')], replyTo: new Address('reply@example.com', 'Reply To'), subject: 'Email to Multiple Recipients', textContent: 'This email is being sent to multiple recipients.', tracking: new TrackingSettings(opens: true, clicks: true) ); $response = $client->sendEmail($email);
Scheduled Email
// Schedule for 24 hours from now $sendTime = time() + (24 * 60 * 60); $email = new Email( from: new Address('sender@example.com'), to: [new Address('user@example.com')], subject: 'Scheduled Email', textContent: 'This email was scheduled.', sendTime: $sendTime, tracking: new TrackingSettings(opens: true, clicks: true) ); $response = $client->sendEmail($email);
Batch Email Sending
$emails = [ new Email( from: new Address('sender@example.com'), to: [new Address('user1@example.com')], subject: 'Email 1', textContent: 'First email content.' ), new Email( from: new Address('sender@example.com'), to: [new Address('user2@example.com')], subject: 'Email 2', textContent: 'Second email content.' ) ]; $response = $client->sendEmails($emails);
Webhook Handler Example
use Laneful\Webhooks\WebhookVerifier; // Complete webhook handler implementation class WebhookController { private string $webhookSecret; public function __construct(string $webhookSecret) { $this->webhookSecret = $webhookSecret; } public function handleWebhook(): void { try { // Extract signature from headers $signature = WebhookVerifier::extractSignatureFromHeaders($_SERVER); if (!$signature) { $this->respond(401, 'Missing signature'); return; } // Get raw payload $payload = file_get_contents('php://input'); // Verify signature if (!WebhookVerifier::verifySignature($this->webhookSecret, $payload, $signature)) { $this->respond(401, 'Invalid signature'); return; } // Parse and validate payload $webhookData = WebhookVerifier::parseWebhookPayload($payload); // Process events foreach ($webhookData['events'] as $event) { $eventType = $event['event']; $email = $event['email']; switch ($eventType) { case 'delivery': error_log("Email delivered to: " . $email); break; case 'open': error_log("Email opened by: " . $email); break; case 'click': $url = $event['url'] ?? 'Unknown URL'; error_log("Link clicked by " . $email . ": " . $url); break; case 'bounce': $isHard = $event['is_hard'] ?? false; error_log("Email bounced (" . ($isHard ? "hard" : "soft") . ") for: " . $email); break; } } $this->respond(200, 'Webhook processed successfully'); } catch (\InvalidArgumentException $e) { $this->respond(400, 'Invalid payload: ' . $e->getMessage()); } catch (Exception $e) { $this->respond(500, 'Processing error: ' . $e->getMessage()); } } private function respond(int $status, string $message): void { http_response_code($status); header('Content-Type: application/json'); echo json_encode(['status' => $status, 'message' => $message]); } }
API Reference
LanefulClient
Constructors
- •
LanefulClient(string $baseUrl, string $authToken)
- Default timeout (30 seconds) - •
LanefulClient(string $baseUrl, string $authToken, int $timeout)
- Custom timeout - •
LanefulClient(string $baseUrl, string $authToken, ?HttpClient $httpClient, int $timeout)
- Custom HTTP client
Methods
- •
array sendEmail(Email $email)
- Send single email - •
array sendEmails(array $emails)
- Send multiple emails
Required Fields
- •
Address $from
- Sender address
Optional Fields
- •
Address[] $to
- Recipient addresses - •
Address[] $cc
- CC recipient addresses - •
Address[] $bcc
- BCC recipient addresses - •
Address|null $replyTo
- Reply-to address - •
string|null $subject
- Email subject - •
string|null $textContent
- Plain text content - •
string|null $htmlContent
- HTML content - •
string|null $templateId
- Template ID - •
array|null $templateData
- Template data - •
Attachment[] $attachments
- File attachments - •
int|null $sendTime
- Scheduled send time - •
TrackingSettings|null $tracking
- Email tracking configuration - •
string|null $tag
- Email tag for categorization
Utility Classes
- •
Address(string $email, ?string $name)
- Email address with optional name - •
Attachment::fromFile(string $filePath, ?string $fileName)
- Create attachment from file - •
TrackingSettings(bool $opens, bool $clicks, bool $unsubscribes)
- Email tracking configuration (opens, clicks, unsubscribes)
WebhookVerifier
Signature Verification
- •
bool verifySignature(string $secret, string $payload, string $signature)
- Verifies webhook signature (supports sha256= prefix) - •
string generateSignature(string $secret, string $payload)
- Generates signature for payload - •
string generateSignature(string $secret, string $payload, bool $includePrefix)
- Generates signature with optional prefix
Payload Processing
- •
array parseWebhookPayload(string $payload)
- Parse and validate webhook payload structure - •
string getSignatureHeaderName()
- Get the correct header name for webhook signatures - •
?string extractSignatureFromHeaders(array $headers)
- Extract signature from HTTP headers
WebhookData
- •
bool is_batch
- Returns true if payload contains multiple events - •
array events
- Returns array of parsed events
Error Handling
Comprehensive error handling with specific exception types:
use Laneful\Exceptions\*; try { $response = $client->sendEmail($email); echo "✓ Email sent successfully!\n"; echo "Response: " . json_encode($response) . "\n"; } catch (ValidationException $e) { // Invalid input data echo "✗ Validation error: " . $e->getMessage() . "\n"; echo "Please check your email configuration\n"; } catch (ApiException $e) { // API returned an error echo "✗ API error: " . $e->getMessage() . "\n"; echo " Status code: " . $e->getCode() . "\n"; echo "Please check your API credentials and endpoint\n"; } catch (HttpException $e) { // Network or HTTP-level error echo "✗ HTTP error: " . $e->getMessage() . "\n"; echo " Status code: " . $e->getCode() . "\n"; echo "Please check your network connection and endpoint URL\n"; } catch (Exception $e) { // Other unexpected errors echo "✗ Unexpected error: " . $e->getMessage() . "\n"; echo $e->getTraceAsString() . "\n"; }
Exception Types
- •
ValidationException
- Input validation fails - •
ApiException
- API returns error response
Methods: getCode(), getMessage() - •
HttpException
- HTTP communication fails
Methods: getCode() - •
LanefulException
- Base exception class
Best Practices
- • Always wrap API calls in try-catch
- • Handle specific exception types first
- • Log errors with context information
- • Implement retry logic for transient failures
Webhook Handling
Comprehensive webhook handling with signature verification, payload parsing, and validation:
Basic Signature Verification
use Laneful\Webhooks\WebhookVerifier; // In your webhook handler $payload = file_get_contents('php://input'); // Get the raw request body $signature = WebhookVerifier::extractSignatureFromHeaders($_SERVER); $secret = 'your-webhook-secret'; if ($signature && WebhookVerifier::verifySignature($secret, $payload, $signature)) { // Process webhook data $webhookData = WebhookVerifier::parseWebhookPayload($payload); // Handle webhook events } else { // Invalid signature http_response_code(401); echo "Invalid webhook signature"; }
Advanced Webhook Processing
use Laneful\Webhooks\WebhookVerifier; // Complete webhook verification and processing workflow try { // Step 1: Get raw payload $payload = file_get_contents('php://input'); // Step 2: Extract signature from headers (supports multiple formats) $signature = WebhookVerifier::extractSignatureFromHeaders($_SERVER); // Step 3: Verify signature (supports sha256= prefix) if (!$signature || !WebhookVerifier::verifySignature($webhookSecret, $payload, $signature)) { throw new SecurityException("Invalid webhook signature"); } // Step 4: Parse and validate payload structure $webhookData = WebhookVerifier::parseWebhookPayload($payload); // Step 5: Process events (handles both batch and single event formats) foreach ($webhookData['events'] as $event) { $eventType = $event['event']; $email = $event['email']; switch ($eventType) { case 'delivery': handleDeliveryEvent($event); break; case 'open': handleOpenEvent($event); break; case 'click': handleClickEvent($event); break; case 'bounce': handleBounceEvent($event); break; case 'drop': handleDropEvent($event); break; case 'spam_complaint': handleSpamComplaintEvent($event); break; case 'unsubscribe': handleUnsubscribeEvent($event); break; } } } catch (\InvalidArgumentException $e) { // Payload validation error http_response_code(400); echo "Invalid payload: " . $e->getMessage(); } catch (Exception $e) { // Other errors http_response_code(401); echo "Processing error: " . $e->getMessage(); }
Batch Mode Support
$webhookData = WebhookVerifier::parseWebhookPayload($payload); if ($webhookData['is_batch']) { // Processing multiple events in batch mode echo "Processing " . count($webhookData['events']) . " events in batch"; } else { // Processing single event echo "Processing single event"; } // Process all events foreach ($webhookData['events'] as $event) { processEvent($event); }
Supported Webhook Events
Delivery Events
- •
delivery
- Email delivered successfully - •
bounce
- Email bounced (hard or soft) - •
drop
- Email dropped (spam, invalid, etc.) - •
spam_complaint
- Recipient marked email as spam
Engagement Events
- •
open
- Email opened by recipient - •
click
- Link clicked in email - •
unsubscribe
- Recipient unsubscribed
Webhook Features
Security
- • HMAC-SHA256 signature verification
- • Support for
sha256=
prefix - • Constant-time comparison (timing attack protection)
- • Multiple header format support
Validation
- • JSON payload structure validation
- • Required field validation
- • Event type validation
- • Email format validation
- • UUID format validation for lane_id
Ready to Get Started?
Start sending emails with PHP in minutes. Check out the examples and integrate with your application.