PHP code example of millionsend / millionsend-php

1. Go to this page and download the library: Download millionsend/millionsend-php 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/ */

    

millionsend / millionsend-php example snippets


use MillionSend\MillionSend;
use MillionSend\Exceptions\ErrorException;

$ms = MillionSend::client('ms_123');                            // MillionSend Cloud
// $ms = MillionSend::client('ms_123', 'https://mail.acme.dev'); // self-hosted

try {
    $email = $ms->emails->send([
        'from' => 'Acme <[email protected]>',
        'to' => '[email protected]',
        'subject' => 'Hello from MillionSend',
        'html' => '<strong>It works!</strong>',
    ]);

    echo "sent {$email['id']}\n";
} catch (ErrorException $e) {
    echo "{$e->getErrorName()}: {$e->getErrorMessage()}\n";
}

MillionSend::client(
    apiKey: 'ms_123',                 // falls back to env MILLIONSEND_API_KEY; missing → throws
    baseUrl: 'https://mail.acme.dev', // falls back to env MILLIONSEND_BASE_URL, then https://api.millionsend.com
    options: [
        'client' => $guzzle,          // inject a GuzzleHttp\ClientInterface (proxies, tests)
        'userAgent' => 'acme-app/2.1', // suffix appended after the SDK's own token
        'timeout' => 30.0,            // total request timeout, seconds
        'connectTimeout' => 10.0,     // connection timeout, seconds
        'allowInsecureHttp' => false, // accept a non-loopback http:// baseUrl
    ],
);

try {
    $email = $ms->emails->get($id);
} catch (ErrorException $e) {
    if ($e->getErrorName() === 'not_found') { /* … */ }
    // $e->getStatusCode(); // int, or null for transport failures
}

$ms->emails->send($payload, ['idempotency_key' => $key]);  // POST /emails
$ms->emails->get($id);                                     // GET /emails/:id ( (reschedule)
$ms->emails->cancel($id);                                  // POST /emails/:id/cancel (scheduled only)
$ms->emails->remove($id);                                  // DELETE /emails/:id (MillionSend extension)
$ms->emails->getInsights($id);                             // GET /emails/:id/insights (404 until computed; MillionSend extension)

$ms->emails->send([
    'from' => 'Acme <[email protected]>',
    'to' => ['[email protected]', '[email protected]'],
    'subject' => 'Launch',
    'html' => '<p>Hi</p>',
    'reply_to' => '[email protected]',
    'scheduled_at' => 'in 1 hour',
    'tags' => [['name' => 'category', 'value' => 'launch']],
    'topic_id' => $topicId,
    'attachments' => [[
        'filename' => 'invoice.pdf',
        'content' => base64_encode($pdf),   // or 'path' => 'https://…'
        'content_type' => 'application/pdf',
    ]],
    'headers' => ['X-Entity-Ref-ID' => '123'],
], ['idempotency_key' => 'order-42']);

// POST /emails/batch — up to 100 emails, one call
$ms->batch->send([$payloadA, $payloadB], [
    'idempotency_key' => $key,
    'batch_validation' => 'permissive', // or 'strict' (server default)
]);

$ms->contacts->create([
    'email' => '[email protected]',
    'first_name' => 'Ada',
    'last_name' => 'Lovelace',
    'unsubscribed' => false,
    'properties' => ['plan' => 'pro'],
    'segments' => [['id' => $segmentId]],
    'topics' => [['id' => $topicId, 'subscription' => 'opt_in']],
]);
$ms->contacts->get('[email protected]');                         // by id or email
$ms->contacts->update('[email protected]', ['first_name' => null, 'unsubscribed' => true]); // null clears
$ms->contacts->update(['id' => $id, 'last_name' => 'L']);   // single-array shape also works
$ms->contacts->remove($id);                                 // the contact's emails stay in the send log
$ms->contacts->remove($id, ['erase' => true]);              // ?erase=true — also scrubs the address from email history, events and API logs (GDPR/LGPD)
$ms->contacts->list(['limit' => 50]);
$ms->contacts->list(['segment_id' => $segmentId]);          // GET /segments/:id/contacts
// Bulk read (MillionSend extension): attach properties and topic subscriptions to every item,
// so an audience reads in one request per 100 contacts instead of one per contact
$ms->contacts->list(['limit' => 100, '422 when the instance cannot build hosted links (self-hosted without APP_BASE_URL)

// Segment membership
$ms->contacts->segments->add($idOrEmail, $segmentId);       // POST /contacts/:id/segments/:segmentId
$ms->contacts->segments->remove($idOrEmail, $segmentId);    // DELETE …

// Bulk create (MillionSend extension) — up to 1000 per call
$result = $ms->contacts->batch->create($contacts, [
    'on_conflict' => 'upsert',          // error (default) | skip | upsert
    'batch_validation' => 'permissive', // strict (default) | permissive
]);
// $result['data'][] = ['index' => 0, 'id' => '…', 'status' => 'created'|'updated'|'skipped']
// $result['counts'] = ['created' => n, 'updated' => n, 'skipped' => n, 'failed' => n]
// $result['errors'][] = ['index' => 3, 'message' => '…']   (permissive mode)

// Bulk lookup (MillionSend extension) — up to 1000 contacts by id or email in one request,
// in request order; unknown entries are listed, not errors — one request against the rate limit
$result = $ms->contacts->batch->get([$contactId, ['email' => '[email protected]']], ['

$ms->contactProperties->create(['key' => 'plan', 'type' => 'string', 'fallback_value' => 'free']);
$ms->contactProperties->list();
$ms->contactProperties->get($id);
$ms->contactProperties->update($id, ['fallback_value' => null]);   // only the fallback is mutable
$ms->contactProperties->remove($id);

$ms->topics->create(['name' => 'Product updates', 'description' => 'Releases', 'default_subscription' => 'opt_in', 'visibility' => 'public']);
$ms->topics->get($id);
$ms->topics->list();     // bare { data } — topics are unpaginated
$ms->topics->update($id, ['name' => 'Product news', 'visibility' => 'private']);
$ms->topics->remove($id);

$broadcast = $ms->broadcasts->create([
    'name' => 'Launch',
    'from' => 'Acme <[email protected]>',
    'subject' => 'Launch',
    'html' => '<p>Hi {{{FIRST_NAME|there}}}</p>',
    'text' => 'Hi',
    'reply_to' => '[email protected]',
    'preview_text' => 'Something new',
    'segment_id' => $segmentId,   // optional
    'topic_id' => $topicId,       // optional
    'send' => true,               // create and send in one call
    'scheduled_at' => '2026-09-01T09:00:00Z',
]);
$ms->broadcasts->list();
$ms->broadcasts->get($id);
$ms->broadcasts->update($id, ['subject' => 'Launch 🚀', 'topic_id' => null]); // draft only; null clears
$ms->broadcasts->send($id, ['scheduled_at' => '2026-09-01T09:00:00Z']);      // omit to send now
$ms->broadcasts->cancel($id);                                                 // scheduled only
$ms->broadcasts->remove($id);                                                 // draft only

$ms->segments->create([
    'name' => 'Pro plan',
    'filter' => [
        'match' => 'all',
        'conditions' => [['field' => 'property:plan', 'op' => 'equals', 'value' => 'pro']],
    ],
]);
$ms->segments->get($id);   // 

$ms->suppressions->add(['email' => '[email protected]', 'origin' => 'manual']); // ->create() is an alias
$ms->suppressions->get($idOrEmail);
$ms->suppressions->list(['origin' => 'bounce', 'limit' => 50]);   // origin: bounce|complaint|manual|unsubscribe
$ms->suppressions->remove($idOrEmail);

$ms->suppressions->batch->add(['emails' => [...], 'origin' => 'unsubscribe']); // up to 1000
$ms->suppressions->batch->remove(['emails' => [...]]);   // or ['ids' => [...]]

$domain = $ms->domains->create([
    'name' => 'acme.dev',
    'region' => 'us-east-1',          // optional
    'custom_return_path' => 'send',   // optional
    'open_tracking' => true,
    'click_tracking' => true,
    'tracking_subdomain' => 'track',
]);
$domain['records'];                    // DNS records to publish
$ms->domains->list();
$ms->domains->get($id);
$ms->domains->verify($id);             // re-check DNS
$ms->domains->update($id, ['open_tracking' => false, 'tracking_subdomain' => null]);
$ms->domains->remove($id);

$hook = $ms->webhooks->create([
    'endpoint' => 'https://acme.dev/hooks/millionsend',
    'events' => ['email.sent', 'email.delivered', 'email.bounced'],
    'signing_secret' => $secret,       // optional — one is generated when omitted
]);
$hook['signing_secret'];
$ms->webhooks->list();
$ms->webhooks->get($id);               // the only read that urs' => 0]); // bring your own; 0..72
$rotated['signing_secret'];
$rotated['previous_secret_expires_at'];  // ISO timestamp while the old secret still co-signs deliveries, else null

$key = $ms->apiKeys->create([
    'name' => 'ci',
    'permission' => 'sending_access',  // full_access (default) | sending_access
    'domain_id' => $domainId,          // optional: restrict a sending key to one domain
]);
$key['token'];                         // shown once, never returned again
$ms->apiKeys->list();
$ms->apiKeys->remove($id);

$ms->templates->create([
    'name' => 'Welcome',
    'html' => '<p>Hi {{{name}}}</p>',
    'subject' => 'Welcome aboard',
    'text' => 'Hi',
    'alias' => 'welcome',
]);
$ms->templates->list();
$ms->templates->get('welcome');
$ms->templates->update('welcome', ['subject' => null, 'html' => '<p>v2</p>']); // null clears alias/subject/text
$ms->templates->remove($idOrAlias);
$ms->templates->publish($idOrAlias);   // no-op on MillionSend (templates are always live); kept for compatibility
$ms->templates->duplicate($idOrAlias);

$report = $ms->deliverability->get();  // GET /deliverability
echo "{$report['score']} ({$report['band']})\n";

$usage = $ms->usage->get();            // GET /usage
$usage['plan'];                        // free | pro | scale | null (self-hosted)
$usage['limits']['emails_per_day'];
$usage['today']['emails_sent'];

$ms->http->request('POST', '/some/new/endpoint', ['key' => 'value']);          // JSON body
$ms->http->request('GET', '/some/new/endpoint', null, ['limit' => 10]);        // query string
$ms->http->request('POST', '/emails', $payload, [], $idempotencyKey);           // Idempotency-Key
// request(string $method, string $path, array|object|null $body = null, array $query = [],
//         ?string $idempotencyKey = null, array $headers = []): array
bash
composer