Skip to content

ThinkPHP

Guide for applications built with ThinkPHP 8 (8.x). Mailexam connects as SMTP through the yzh52521/think-mail package (Symfony Mailer).

What you need

  • A Mailexam account and a project with SMTP credentials.
  • ThinkPHP 8 and Composer.

Copy from the welcome email (or dashboard) for your project:

  • YOUR_LOGIN — SMTP login (for example, xxxxx);
  • YOUR_PASSWORD — SMTP password (a unique pair with the login);
  • host — YOUR_LOGIN.mailexam.io (matches the login).

1. Dependencies

composer require yzh52521/think-mail
composer require vlucas/phpdotenv  # for .env in local development

After installation, config/mailer.php appears in the project. Customize it for Mailexam (see below).

2. Environment variables

.env file in the project root (add to .gitignore):

MAILEXAM_LOGIN=YOUR_LOGIN
MAILEXAM_PASSWORD=YOUR_PASSWORD
MAILEXAM_PORT=587
MAIL_FROM=noreply@example.test

Load .env at startup (for example, in public/index.php before creating the application):

Dotenv\Dotenv::createImmutable(dirname(__DIR__))->safeLoad();

Host in configuration: YOUR_LOGIN.mailexam.io.

Sender address

MAIL_FROM can be any test address — the message goes to Mailexam, not to a real recipient.

Alternative ports

MAILEXAM_PORT=587
MAILEXAM_PORT=2525
MAILEXAM_PORT=465
MAILEXAM_PORT=25

3. SMTP configuration

config/mailer.php:

<?php

$login = getenv('MAILEXAM_LOGIN') ?: '';
$port = (int) (getenv('MAILEXAM_PORT') ?: 587);
$from = getenv('MAIL_FROM') ?: 'noreply@example.test';

return [
    'scheme' => 'smtp',
    'host' => $login . '.mailexam.io',
    'username' => $login,
    'password' => getenv('MAILEXAM_PASSWORD') ?: '',
    'port' => $port,
    'options' => [],
    'embed' => 'cid:',
    'from' => [
        'address' => $from,
        'name' => 'Mailexam Test',
    ],
];

For complex mail flows, use templates and attachments from think-mail — the SMTP settings stay the same.

4. Sending a test email

Via HTTP (controller)

// app/controller/Mail.php
namespace app\controller;

use app\BaseController;
use mailer\facade\Mailer;

class Mail extends BaseController
{
    public function test()
    {
        $payload = $this->request->post();
        if ($payload === []) {
            $payload = json_decode($this->request->getContent(), true) ?? [];
        }

        $to = $payload['to'] ?? 'user@example.test';
        $subject = $payload['subject'] ?? 'ThinkPHP + Mailexam';
        $body = $payload['body'] ?? $payload['text'] ?? 'Mailexam test from ThinkPHP';

        Mailer::to($to)->subject($subject)->text($body)->send();

        return json(['status' => 'ok']);
    }
}

Route in route/app.php:

use think\facade\Route;

Route::post('mail/test', 'mail/test');

Start and verify:

php -S 127.0.0.1:8080 -t public public/router.php
curl -X POST http://127.0.0.1:8080/mail/test \
  -H 'Content-Type: application/json' \
  -d '{"to":"user@example.test","subject":"Test","body":"Hello"}'

The message will appear in the Mailexam dashboard → your project → inbox.

5. Local development and CI

Environment Recommendation
local .env with Mailexam credentials
CI Variables MAILEXAM_LOGIN, MAILEXAM_PASSWORD in pipeline secrets

Example for GitLab CI:

variables:
  MAILEXAM_LOGIN: $MAILEXAM_LOGIN
  MAILEXAM_PASSWORD: $MAILEXAM_PASSWORD
  MAILEXAM_PORT: "587"
  MAIL_FROM: "noreply@example.test"

After sending a message in the pipeline, verify delivery via the Mailexam API.

6. Common issues

TLS or authentication failed

  • host must be {login}.mailexam.io, username — the same login from the email.
  • Login and password are a pair from the email for one project.

Environment variables are empty

  • Call Dotenv::createImmutable(...)->safeLoad() before (new App())->http.
  • In production, set variables in the PHP-FPM / container environment.

Message not in the dashboard

  • View the inbox of the same Mailexam project.
  • Check runtime/log/ for SMTP errors.

See also