Skip to main content

Sending over SMTP

Arsel provides a standard SMTP server that lets you send transactional emails using any SMTP client. This is ideal when your application already sends emails through SMTP and you want to route them through Arsel without changing your code.

When to use SMTP vs the API​

SMTPREST API
Best forExisting apps with SMTP code, legacy systems, platforms that only support SMTPNew integrations, full control over request/response, programmatic workflows
AuthenticationUsername + password per connectionAPI key per request
FeaturesSend emails with HTML, text, attachmentsSend emails + list status + per-recipient tracking + SMS
Rate limiting50 messages/sec per organization, 421 reply (closes connection) when blocked1,000 requests/min per organization, 429 with rate-limit headers
TrackingFull delivery tracking via the API status endpointsFull delivery tracking built-in
tip

Emails sent via SMTP are processed through the same pipeline as API emails. You get the same delivery infrastructure, tracking, and analytics regardless of which method you use.

Connection details​

SettingValue
Hostsmtp.arsel.sa
Port465 (implicit TLS)
SecurityTLS required
AuthenticationPLAIN or LOGIN
Max message size30 MB

Quick start​

  1. Create SMTP credentials from your Arsel Dashboard under Integration > SMTP Credentials. See Managing credentials below.

  2. Configure your SMTP client with the connection details above and your generated username and password.

  3. Send an email through your application's existing email flow.

See SMTP client setup for detailed examples across languages and frameworks.

Requirements​

Before sending via SMTP, ensure:

  • Your sender domain is verified in the Arsel dashboard — see Domain verification
  • Your SMTP credentials are active (not revoked)
  • Your organization's sending quota has not been exceeded
  • Your organization is not suspended due to bounce/complaint rates — see Sender reputation

Recipients​

Arsel delivers to the envelope recipients — the addresses your client passes in RCPT TO — exactly as any standard SMTP server does. The To: and Cc: headers control only what the recipient sees.

In practice your SMTP library already handles this and you do not need to do anything special:

  • BCC works normally. Most clients (Nodemailer, Python's smtplib.send_message, JavaMail) deliberately strip the Bcc: header before sending and carry blind recipients in the envelope only. Those recipients receive the message, and the other recipients cannot see them.
  • An address in To: that you did not RCPT TO is not a recipient. This is what lets you send a message addressed to To: members@yourdomain.com while delivering an individual copy to each member.
  • Envelope addresses that appear in no header are treated as blind copies.
LimitValue
Recipients per message (To + Cc + Bcc combined)50

The 51st RCPT TO in a message is answered with 452 Too many recipients (RFC 5321 §4.5.3.1.10). The first 50 are still accepted, and standard clients send the remaining recipients in a follow-up message. SMTP is built for per-recipient transactional mail, not bulk sends.

Managing credentials​

SMTP credentials are organization-scoped username/password pairs used to authenticate SMTP connections. Each credential set is independent — you can create multiple credentials for different applications or environments.

Creating credentials​

Generate SMTP credentials from your Arsel dashboard:

  1. Navigate to Integration > SMTP Credentials
  2. Click Create Credentials
  3. Optionally give them a descriptive name (e.g., "Production Server", "Staging")
  4. Copy the username and password immediately
warning

The password is only shown once at creation time. Store it securely — it cannot be retrieved later. If lost, rotate the credential to generate a new password.

Credential format​

FieldFormatExample
Usernamesmtp_ + 16 random characterssmtp_aB3xK9mP2qR5wY7z
Passwordsk_ + 32 random characterssk_4f8Hj2kLmN6pQrStUvWxYz1a3B5cD7e

Credential lifecycle​

Active credentials. New credentials are active by default. Active credentials can authenticate SMTP connections and send emails.

Rotating. If a credential may have been compromised, or as part of regular security hygiene, you can rotate it:

  1. Navigate to Integration > SMTP Credentials
  2. Click Rotate on the credential
  3. Copy the new password immediately
  4. Update your application's SMTP configuration
  5. The old password is immediately invalidated
tip

To rotate with zero downtime: create a new credential, update your application to use it, then revoke the old one.

Revoking. Revoking a credential disables it without deleting it. This is useful for temporarily disabling access:

  1. Click Revoke on the credential
  2. Any active SMTP sessions using this credential will fail on the next authentication
  3. The credential can be re-enabled later by updating its status

Deleting. Deleting a credential permanently removes it. This cannot be undone:

  1. Click Delete on the credential
  2. Confirm the deletion
  3. The credential is permanently removed

Security best practices​

  • Use separate credentials for each environment (development, staging, production)
  • Use separate credentials for each application or service that sends emails
  • Rotate credentials regularly as part of your security policy
  • Revoke immediately if a credential may have been exposed
  • Never commit credentials to source control — use environment variables or secrets management
  • Monitor last-used timestamps in the dashboard to identify unused credentials

Tracking usage​

The dashboard shows for each credential:

FieldDescription
NameOptional label you assigned
UsernameThe SMTP username
StatusActive or Revoked
Last UsedTimestamp of the most recent authentication
CreatedWhen the credential was generated

Attachments​

LimitValue
Attachments per message10
Message size, as sent30 MB

The size limit applies to the whole message as your client transmits it. Attachments are base64-encoded on the wire, which adds about a third, so the practical ceiling is roughly 22 MB of attachments. A larger message is refused with 552: before the upload if your client declares the message size (most libraries do when the server advertises SIZE), otherwise at the end of DATA.

Allowed types: PDF, Word, Excel, PowerPoint, RTF, plain text, CSV, JSON, XML, ZIP, calendar invites (.ics), and JPEG/PNG/GIF/WebP/SVG images.

If your client labels attachments application/octet-stream — many do, including Outlook and most smtplib scripts — Arsel resolves the real type from the filename extension, so invoice.pdf is accepted as a PDF. Give every attachment a filename with the correct extension and this is transparent.

An attachment that is not an allowed type, or whose extension is on the executable blocklist, causes the whole message to be rejected with:

552 Attachment rejected: disk.iso, payload.exe

The message is not sent and no partial copy goes out, so you can fix the attachment and resend safely.

Attachments are held encrypted only while the message is being delivered and are deleted once it has been sent.

Inline images​

Images embedded in the HTML with cid: references — a logo, a signature — are delivered inline, in their multipart/related structure, exactly as your client built them. Nodemailer's cid attachments, MIMEImage with a Content-ID in Python, and Outlook's embedded images all work unchanged. Inline images count toward the attachment limits above.

Calendar invites​

A calendar invite is delivered so that Gmail, Outlook and Apple Mail show it as an invite with accept/decline buttons, not as a file. Send it the way your library normally does. Nodemailer's icalEvent, or a text/calendar part with a method parameter such as REQUEST or CANCEL, keeps its method. An .ics file sent as an ordinary attachment is delivered as an attachment.

Rate limits​

Each organization can submit 50 messages per second in production. The limit is shared across all SMTP credentials and concurrent connections — additional credentials do not raise your throughput.

When you exceed it, the server replies to your DATA command with:

421 Too many messages, please slow down

and closes the connection (RFC 5321 §3.8). Your next message opens a fresh session. The limit is a 1-second window aligned to the wall clock, so backing off slightly more than one second is the safest pattern.

Things to know:

  • The check runs after the message body has streamed. There's no way to pre-flight at MAIL FROM or RCPT TO — a throttled message still pays full upload cost.
  • The slot is consumed even when the message later fails downstream validation (unverified sender, bad recipients). Fix the underlying error first — retrying a doomed message burns rate budget.
  • The monthly sending quota is a separate limit and returns 451 Monthly sending quota exceeded (connection stays open). Waiting a second won't clear it.

Handling rate limits​

When you see 421 Too many messages:

  • Match on code 421 and the text Too many messages. Don't blanket-retry every 421 — other causes (restarts, maintenance) are not the same condition.
  • Open a new connection. The old one is closed. Pooled libraries (Nodemailer pool, JavaMail) reopen automatically; ad-hoc clients construct a fresh transport.
  • Back off exponentially with jitter, e.g. 1s × 2^attempt capped at ~10 s, and stop after about 5 attempts. Surface persistent failures to a dead-letter queue or your upstream caller.
  • Prefer prevention. If you regularly hit the limit, add a client-side token bucket sized to 50 msg/s/org — back-pressure is cheaper than reactive retries, since 421 only fires after the body has finished uploading.

The REST API has its own separate limit — see Rate limiting.

Concurrent connections​

Each organization can hold up to 20 authenticated connections at once, across all of its credentials. Authenticating a 21st returns:

421 Too many concurrent connections for this organization, retry later

and closes that connection; the ones already open are unaffected. A pool of 5–10 connections comfortably covers the 50 messages/second limit, because each connection can carry many messages. In Nodemailer, set pool: true with maxConnections at 10 or less. Idle connections are closed after 60 seconds, and pooled clients reconnect on their own.

Safe retries (X-Idempotency-Key)​

Every transient SMTP reply — 421, 451 — asks you to retry, and so does a connection that drops after you send DATA but before you read the reply. In that last case the message may already have been accepted, and a blind retry sends it twice.

Set an X-Idempotency-Key header to make a retry safe:

X-Idempotency-Key: order-1001-shipped
  • The first message with a given key is processed normally.
  • Any later message with the same key, within 24 hours, is accepted with 250 and not sent again.
  • After 24 hours the key expires and may be reused.

The key is any unique string of up to 256 characters. A value derived from what the message is about — order-1001-shipped, interview-invite-8842 — is better than a random UUID, because your retry path can regenerate it identically without having stored it.

Example​

await transporter.sendMail({
from: "notifications@yourdomain.com",
to: "candidate@example.com",
subject: "Your interview is confirmed",
text: "See you on Thursday.",
headers: {
"X-Idempotency-Key": `interview-invite-${interviewId}`,
},
});
msg["X-Idempotency-Key"] = f"interview-invite-{interview_id}"

Error replies​

ReplyMeaningRetry?
501The key is empty or longer than 256 charactersNo — fix the key
554The key was already used with a different messageNo — use a fresh key
451A message with this key is still being processedYes — after a short delay
Reusing a key for a different message

The key is bound to the message it was first used with. Sending different content under a key that is already in use is rejected with 554 rather than silently replacing the original. Use a fresh key for a genuinely different message.

tip

Keys are scoped per organization. SMTP and the REST send email endpoint share one key space, because both send the same email, so a key used on one path is answered from that record on the other. Use keys that are unique across both.