Get started

On this page

Sending email from your app

Testlie speaks plain SMTP, so your app keeps its normal mail code: change the SMTP settings in the environment you want to capture (development, staging, CI) and every message lands in an inbox instead of reaching real people.

SMTP settings

Each inbox has its own credentials, on its SMTP settings tab:

Setting Value
Host smtp.testlie.com
Port 587, 2525, 465
Username the inbox's username (14 hex characters)
Password the inbox's password (shown to team members; admins can rotate it)
Authentication PLAIN or LOGIN
Encryption STARTTLS on the plain ports when the server has a certificate; implicit TLS on 465 if it is listed

The credentials decide the inbox, not the recipient: mail sent with an inbox's username lands in that inbox whatever the To, Cc and Bcc addresses are. Bcc recipients are shown in the viewer from the SMTP envelope.

When the server has TLS configured, it only offers and accepts AUTH on a connection that has been upgraded with STARTTLS (unless the operator set SMTP_ALLOW_INSECURE_AUTH=true). Most clients upgrade automatically; the snippets below enable it where they do not.

Tip: an empty inbox in the app shows all of these snippets already filled in with its real host, port and credentials.

Inbound address

If the server has an inbound domain, each inbox also has its own address, <alias>@in.testlie.com, shown on the SMTP settings tab. Mail sent to it from anywhere (no credentials needed) lands in the inbox. Use it to test flows where a real third party sends you mail, such as a sign-up confirmation from a SaaS vendor.

Node.js (nodemailer)

js
import nodemailer from "nodemailer";

const transport = nodemailer.createTransport({
  host: "smtp.testlie.com",
  port: 587,
  secure: false, // true only for port 465; STARTTLS is used automatically when offered
  auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS },
});

await transport.sendMail({
  from: "app@example.com",
  to: "new-user@example.com",
  subject: "Welcome aboard",
  html: "<h1>Hi!</h1><a href='https://app.example.com/verify'>Verify</a>",
});

Python (smtplib)

python
import os, smtplib
from email.message import EmailMessage

msg = EmailMessage()
msg["From"] = "app@example.com"
msg["To"] = "new-user@example.com"
msg["Subject"] = "Welcome aboard"
msg.set_content("Hi! Verify your account: https://app.example.com/verify")
msg.add_alternative("<h1>Hi!</h1><a href='https://app.example.com/verify'>Verify</a>", subtype="html")

with smtplib.SMTP("smtp.testlie.com", 587) as smtp:
    smtp.starttls()  # omit if the server has no TLS certificate
    smtp.login(os.environ["SMTP_USER"], os.environ["SMTP_PASS"])
    smtp.send_message(msg)

Django

python
# settings/staging.py
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "smtp.testlie.com"
EMAIL_PORT = 587
EMAIL_HOST_USER = os.environ["SMTP_USER"]
EMAIL_HOST_PASSWORD = os.environ["SMTP_PASS"]
EMAIL_USE_TLS = True   # STARTTLS; set False if the server has no certificate
# For port 465 use EMAIL_USE_SSL = True instead (and EMAIL_USE_TLS = False).

send_mail(...), EmailMessage and password-reset emails from django.contrib.auth all go through this backend.

Ruby on Rails (Action Mailer)

ruby
# config/environments/staging.rb
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
  address: "smtp.testlie.com",
  port: 587,
  user_name: ENV["SMTP_USER"],
  password: ENV["SMTP_PASS"],
  authentication: :plain,
  enable_starttls_auto: true
}
config.action_mailer.default_url_options = { host: "staging.example.com" }

PHP (Laravel)

ini
# .env
MAIL_MAILER=smtp
MAIL_HOST=smtp.testlie.com
MAIL_PORT=587
MAIL_USERNAME=your-inbox-username
MAIL_PASSWORD=your-inbox-password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=app@example.com

Use MAIL_ENCRYPTION=null when the server has no certificate, or ssl with port 465. Plain PHP with PHPMailer works the same way: $mail->isSMTP(); $mail->Host = 'smtp.testlie.com'; $mail->Port = 587; $mail->SMTPAuth = true;.

Java (Spring Boot)

properties
# application-staging.properties
spring.mail.host=smtp.testlie.com
spring.mail.port=587
spring.mail.username=${SMTP_USER}
spring.mail.password=${SMTP_PASS}
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true

Inject JavaMailSender and send as usual:

java
@Autowired JavaMailSender mailSender;

var message = new SimpleMailMessage();
message.setFrom("app@example.com");
message.setTo("new-user@example.com");
message.setSubject("Welcome aboard");
message.setText("Hi! Verify your account: https://app.example.com/verify");
mailSender.send(message);

.NET (MailKit)

System.Net.Mail.SmtpClient still works, but Microsoft recommends MailKit:

csharp
// dotnet add package MailKit
using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;

var message = new MimeMessage();
message.From.Add(MailboxAddress.Parse("app@example.com"));
message.To.Add(MailboxAddress.Parse("new-user@example.com"));
message.Subject = "Welcome aboard";
message.Body = new TextPart("html") { Text = "<h1>Hi!</h1>" };

using var client = new SmtpClient();
await client.ConnectAsync("smtp.testlie.com", 587, SecureSocketOptions.StartTlsWhenAvailable);
await client.AuthenticateAsync(Environment.GetEnvironmentVariable("SMTP_USER"), Environment.GetEnvironmentVariable("SMTP_PASS"));
await client.SendAsync(message);
await client.DisconnectAsync(true);

Go (net/smtp)

go
package main

import (
	"net/smtp"
	"os"
)

func main() {
	// SendMail upgrades with STARTTLS when the server offers it. PlainAuth refuses to send a
	// password over an unencrypted connection, except to localhost.
	auth := smtp.PlainAuth("", os.Getenv("SMTP_USER"), os.Getenv("SMTP_PASS"), "smtp.testlie.com")
	msg := []byte("From: app@example.com\r\n" +
		"To: new-user@example.com\r\n" +
		"Subject: Welcome aboard\r\n\r\n" +
		"Hi! Verify your account: https://app.example.com/verify\r\n")
	err := smtp.SendMail("smtp.testlie.com:587", auth, "app@example.com", []string{"new-user@example.com"}, msg)
	if err != nil {
		panic(err)
	}
}

Limits and errors

SMTP reply Meaning
535 Wrong username or password. Copy them again from the inbox, or check whether an admin rotated the password.
538 The server requires STARTTLS before AUTH. Enable STARTTLS in your client.
530 The client did not authenticate, and the recipient is not an inbox's inbound address. Set the username and password.
552 The message is larger than the plan's (or the server's) maximum size.
451 The inbox received more messages per minute than the plan allows. Retry shortly; most mail libraries do.
550 The team's monthly message quota is used up (or the inbox was deleted). See Plans & limits.
421 Too many connections, concurrent sessions or failed logins from your IP address. Wait a minute and retry.