Appearance
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
| Setting | Value |
|---|---|
| Host | smtp.krafter.dev |
| Port | 465 |
| Encryption | TLS (implicit, required) |
| Username | apikey |
| Password | Your 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: :alwaysDjango (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
- Install the WP Mail SMTP plugin.
- Go to WP Mail SMTP > Settings.
- Select Other SMTP as the mailer.
- Enter the following settings:
- SMTP Host:
smtp.krafter.dev - Encryption: SSL
- SMTP Port:
465 - SMTP Username:
apikey - SMTP Password: Your API key
- SMTP Host:
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| Value | Behaviour |
|---|---|
| (header absent) | Defaults to transactional |
transactional | Uses the transactional stream (default tracking_enabled: false) |
broadcast | Uses the broadcast stream (default tracking_enabled: true, list-unsubscribe header added) |
| anything else | Rejected 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
transactionalstream, default isfalse. Set totrueto opt this single send into tracking. - On the
broadcaststream, default istrue. Set tofalseto 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:sendscope.
550 rejection
unknown stream: ...—X-Krafter-Streamwas set to a value other thantransactionalorbroadcast.API key is not allowed to send on stream '...'— your API key'sallowed_streamsdoes 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.