BETA
Skip to content

SMTP Relay

Krafter Mail provides an SMTP relay for applications that send email through SMTP rather than a REST API. This is useful for legacy systems, CMS platforms, and any software that supports SMTP configuration.

Connection Details

SettingValue
Hostsmtp.krafter.dev
Port465
EncryptionTLS (implicit, required)
Usernameapikey
PasswordYour API key (e.g., kr_live_abc123def456)

INFO

Port 465 uses implicit TLS (SMTPS), which means the connection is encrypted from the start. This is more secure and reliable than STARTTLS on port 587.

Quick Test with swaks

You can test the SMTP relay from the command line using swaks:

bash
swaks \
  --to recipient@example.com \
  --from hello@yourdomain.com \
  --server smtp.krafter.dev \
  --port 465 \
  --tls \
  --auth-user apikey \
  --auth-password kr_live_abc123def456 \
  --header "Subject: SMTP Test" \
  --body "This email was sent via Krafter Mail SMTP relay."

Configuration Examples

Nodemailer (Node.js)

typescript
import nodemailer from "nodemailer";

const transporter = nodemailer.createTransport({
  host: "smtp.krafter.dev",
  port: 465,
  secure: true, // implicit TLS
  auth: {
    user: "apikey",
    pass: process.env.KRAFTER_API_KEY,
  },
});

await transporter.sendMail({
  from: "hello@yourdomain.com",
  to: "recipient@example.com",
  subject: "Hello from Krafter Mail",
  html: "<h1>Welcome!</h1><p>Sent via SMTP relay.</p>",
});

Swoosh (Elixir / Phoenix)

elixir
# config/runtime.exs
config :my_app, MyApp.Mailer,
  adapter: Swoosh.Adapters.SMTP,
  relay: "smtp.krafter.dev",
  port: 465,
  username: "apikey",
  password: System.get_env("KRAFTER_API_KEY"),
  ssl: true,
  tls: :never,
  auth: :always

Django (Python)

python
# settings.py
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "smtp.krafter.dev"
EMAIL_PORT = 465
EMAIL_USE_SSL = True  # implicit TLS on port 465
EMAIL_HOST_USER = "apikey"
EMAIL_HOST_PASSWORD = os.environ.get("KRAFTER_API_KEY")
DEFAULT_FROM_EMAIL = "hello@yourdomain.com"

Laravel (PHP)

php
// .env
MAIL_MAILER=smtp
MAIL_HOST=smtp.krafter.dev
MAIL_PORT=465
MAIL_USERNAME=apikey
MAIL_PASSWORD=kr_live_abc123def456
MAIL_ENCRYPTION=ssl
MAIL_FROM_ADDRESS=hello@yourdomain.com
MAIL_FROM_NAME="My App"

Ruby on Rails

ruby
# config/environments/production.rb
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
  address: "smtp.krafter.dev",
  port: 465,
  user_name: "apikey",
  password: ENV["KRAFTER_API_KEY"],
  authentication: :plain,
  ssl: true,
}

WordPress

  1. Install the WP Mail SMTP plugin.
  2. Go to WP Mail SMTP > Settings.
  3. Select Other SMTP as the mailer.
  4. Enter the following settings:
    • SMTP Host: smtp.krafter.dev
    • Encryption: SSL
    • SMTP Port: 465
    • SMTP Username: apikey
    • SMTP Password: Your API key

Authentication

SMTP authentication uses the same API keys as the REST API. The username is always the literal string apikey, and the password is your actual API key.

The API key must have the mail:send scope to send emails via SMTP.

Per-message headers

Two custom request headers control routing and tracking for an individual SMTP message. Add them to the message your client sends, alongside From:, To:, etc.

X-Krafter-Stream

Selects the stream for this message:

X-Krafter-Stream: transactional
ValueBehaviour
(header absent)Defaults to transactional
transactionalUses the transactional stream (default tracking_enabled: false)
broadcastUses the broadcast stream (default tracking_enabled: true, list-unsubscribe header added)
anything elseRejected with SMTP 550 (invalid_stream)

If your API key's allowed_streams does not include the requested stream, the message is rejected with SMTP 550 (stream_not_allowed).

X-Krafter-Tracking-Enabled

Per-message override for open/click tracking. Case-insensitive true or false; any other value is ignored:

X-Krafter-Tracking-Enabled: false
  • On the transactional stream, default is false. Set to true to opt this single send into tracking.
  • On the broadcast stream, default is true. Set to false to opt this single send out.

Tracking itself is applied through the SES configuration set attached to the resolved policy. Krafter does not insert HTML pixels or rewrite links in your message body — tracking is configured at the SES level per stream.

Policy enforcement and error codes

SMTP messages are routed through the same SenderPolicy pipeline as REST sends. If the request violates a policy rule (stream not allowed, sandbox cap exceeded, sandbox extra recipients, etc.), the server replies with:

  • 550 <message> — permanent failure: stream not allowed, invalid stream, sandbox policy violation, recipient outside the sandbox allow-list.
  • 451 Temporary failure, try again later — transient failure: an unexpected error while creating the email record.

The <message> text mirrors the human-readable error you would receive from the REST API.

Limitations

  • Port: Only port 465 (implicit TLS) is supported. Ports 25 and 587 are not available.
  • Maximum message size: 25 MiB (26,214,400 bytes), including attachments. Larger messages are rejected by the SMTP server.
  • No STARTTLS: Only implicit TLS (port 465) is supported, not STARTTLS (port 587).

Troubleshooting

Connection refused

Ensure you are connecting to port 465 with TLS/SSL enabled. Connections to ports 25 or 587 will be refused.

Authentication failed

  • Verify your API key is correct and has not been revoked.
  • Make sure the username is the literal string apikey (not your email address).
  • Confirm the API key has the mail:send scope.

550 rejection

  • unknown stream: ...X-Krafter-Stream was set to a value other than transactional or broadcast.
  • API key is not allowed to send on stream '...' — your API key's allowed_streams does not include the requested stream.
  • Sandbox-related messages — see Error handling for the full enum.

Certificate errors

If your SMTP client reports certificate issues, ensure it is configured to use TLS/SSL (not STARTTLS) and that your system's CA certificates are up to date.

Built by Krafter Studio