Updated 2026-10-08

How to Send Email with PHPMailer over SMTP

To send email with PHPMailer through an SMTP relay, call isSMTP() and set Host to smtp.bulko.io, SMTPAuth to true, Username and Password from environment variables, SMTPSecure to PHPMailer::ENCRYPTION_STARTTLS and Port to 587. For port 465 use PHPMailer::ENCRYPTION_SMTPS instead.

Hostsmtp.bulko.io
Port587 · 465 · 2525
EncryptionSTARTTLS · SSL
Loginfrom dashboard

PHPMailer SMTP settings

FieldValue
Hostsmtp.bulko.io
SMTPAuthtrue
Usernamegetenv('SMTP_USERNAME') (e.g. smtp_xxxxxxxxxxxxxxxx)
Passwordgetenv('SMTP_PASSWORD')
SMTPSecurePHPMailer::ENCRYPTION_STARTTLS for 587/2525, PHPMailer::ENCRYPTION_SMTPS for 465
Port587 (or 2525 if blocked, 465 with SMTPS)
setFrom()An address on your domain, e.g. [email protected]

Step-by-step setup

  1. Buy an SMTP package on the Bulko SMTP Relay page and copy the username and password from Dashboard -> SMTP Access.
  2. Install PHPMailer with composer require phpmailer/phpmailer and load vendor/autoload.php.
  3. Expose the credentials as environment variables SMTP_USERNAME and SMTP_PASSWORD (web server, PHP-FPM pool config or your framework's .env loader) and read them with getenv().
  4. Create new PHPMailer(true) so errors throw exceptions, call isSMTP(), then set Host, SMTPAuth = true, Username and Password.
  5. Match encryption to the port. PHPMailer::ENCRYPTION_STARTTLS (the string tls) goes with 587 or 2525. PHPMailer::ENCRYPTION_SMTPS (the string ssl) goes with 465. Mixing them is the most common PHPMailer SMTP error.
  6. Call setFrom() with an address on your own domain. For aligned SPF, DKIM and DMARC, verify the domain under Sending Domains in the Bulko dashboard.
  7. Set the content (Subject, Body, AltBody) and call send() inside try, printing $mail->ErrorInfo on failure.

Shared hosting sometimes blocks outbound 587 and 465. In that case keep ENCRYPTION_STARTTLS and set Port = 2525. More detail in the SMTP ports guide.

send-test.php

<?php
// send-test.php  (composer require phpmailer/phpmailer)
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;

require __DIR__ . '/vendor/autoload.php';

$mail = new PHPMailer(true); // true = throw exceptions on errors

try {
    // $mail->SMTPDebug = SMTP::DEBUG_SERVER; // uncomment to print the SMTP dialogue
    $mail->isSMTP();
    $mail->Host       = 'smtp.bulko.io';
    $mail->SMTPAuth   = true;
    $mail->Username   = getenv('SMTP_USERNAME');
    $mail->Password   = getenv('SMTP_PASSWORD');
    $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; // 587 or 2525
    $mail->Port       = 587;
    // Port 465 instead:
    // $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
    // $mail->Port       = 465;

    $mail->CharSet = PHPMailer::CHARSET_UTF8;
    $mail->setFrom('[email protected]', 'Your App');
    $mail->addAddress('[email protected]');
    $mail->Subject = 'PHPMailer SMTP test';
    $mail->isHTML(true);
    $mail->Body    = '<p>It works.</p>';
    $mail->AltBody = 'It works.';

    $mail->send();
    echo "Message sent\n";
} catch (Exception $e) {
    echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}\n";
}

Send a test email

Run SMTP_USERNAME=smtp_xxx SMTP_PASSWORD=yourpass php send-test.php from the command line with a real recipient in addAddress(). Message sent means the relay accepted the message; check the inbox within a minute or two.

If it fails, uncomment $mail->SMTPDebug = SMTP::DEBUG_SERVER; and run again. The output shows every SMTP command and reply, so you can see whether the problem is the connection, the TLS handshake, authentication (535) or content (554 5.7.1). Turn debug off again before going to production.

Troubleshooting

ProblemFix
SMTP Error: Could not authenticate.Wrong username or password, or getenv() returns false because the variables are not set for the PHP process. See https://bulko.io/en/smtp-errors/535/
SMTP Error: Could not connect to SMTP host.Port blocked by the host or wrong SMTPSecure for the port. Try Port 2525 with ENCRYPTION_STARTTLS, and check the debug output.
SSL routines: wrong version numberENCRYPTION_SMTPS was used with port 587. Use ENCRYPTION_STARTTLS on 587, or switch Port to 465.
Connection hangs, then times out on 465ENCRYPTION_STARTTLS was used with port 465. Port 465 needs ENCRYPTION_SMTPS.
Class "PHPMailer\PHPMailer\PHPMailer" not foundThe autoloader is not loaded or the package is not installed. Run composer require phpmailer/phpmailer and require vendor/autoload.php.
SMTP Error: data not accepted (554 5.7.1)The AI content filter rejected the message for phishing, malware, impersonation or scam patterns. See https://bulko.io/en/acceptable-use/

FAQ

Should SMTPSecure be tls or ssl in PHPMailer?

Use PHPMailer::ENCRYPTION_STARTTLS (tls) with port 587 or 2525, and PHPMailer::ENCRYPTION_SMTPS (ssl) with port 465. The constants are clearer than the raw strings.

Why use PHPMailer instead of PHP mail()?

mail() hands the message to the local sendmail with no SMTP authentication, so it often lands in spam or is blocked by the host. PHPMailer authenticates to a real SMTP relay.

Can PHPMailer read incoming email from this server?

No. Bulko SMTP is outgoing only, with no IMAP or inbox. Replies go to the From or Reply-To address you set.

Is there a sending limit?

The default is 2,000 emails per day per SMTP account. Contact [email protected] to raise it.

How much does it cost?

One-time packages: $5 for 5,000 emails, $15 for 20,000, $30 for 50,000, $60 for 150,000. Unused emails never expire and there is no free SMTP trial.

Get SMTP credentials for PHPMailer

One-time payment by card or crypto, no subscription. Unused emails never expire. 2,000 emails per day per SMTP account.

SMTP Relay 5K: $5 · 5000SMTP Relay 20K: $15 · 20000SMTP Relay 50K: $30 · 50000SMTP Relay 150K: $60 · 150000
See SMTP relay plans

What you can send: Acceptable Use Policy.