Rails SMTP email is a practical choice when your application already uses Action Mailer and you want to send transactional messages without replacing your mailer layer. This guide configures a Rails app to submit a welcome email through Volanea over SMTP, with credentials loaded from environment variables rather than hard-coded in application code.

The integration uses Rails’ built-in Action Mailer SMTP delivery method. That means there is no Volanea-specific Ruby SDK to install for the SMTP path: Action Mailer builds the MIME message, authenticates to the SMTP relay, and submits the message on your behalf. Volanea handles the relay side after the connection succeeds.

Use this approach for transactional messages generated by your application, including password resets, account verification, invoices, receipts, invitations, notifications, and security alerts. For campaign sending, keep the same discipline around sender identity, consent, recipient quality, and delivery monitoring.

What you need before configuring Rails SMTP email

Before adding SMTP settings, make sure you have the following pieces in place:

  • A Rails application with Action Mailer available. Full Rails applications include it by default.
  • A Volanea account with SMTP sending enabled for your workspace.
  • SMTP relay connection details from Volanea: server address, port, username, and the TLS mode expected for that port.
  • A Volanea API key or SMTP credential that is permitted to authenticate to the relay.
  • A sender address on a domain that has been configured for sending in Volanea.
  • A safe recipient address you control for the first delivery test.

SMTP has two separate layers that are easy to confuse. The first is submission: your Rails app opens a connection to the relay, negotiates encryption, authenticates, and transfers a message. The second is delivery: the relay evaluates the sender and recipient, applies its sending policy, and attempts delivery to the recipient’s mail server.

A successful Rails call proves that submission completed. It does not always prove that the message reached the inbox. Treat the first test as a sequence: confirm the Rails process can authenticate, confirm the sender is accepted, then inspect delivery events and the receiving mailbox.

Do not put a Volanea API key directly in config/environments/production.rb, a mailer, a job argument, a source-controlled YAML file, or a committed .env file. Credentials are secrets. Your production platform should inject them as environment variables or through its secret manager.

How Rails sends email through SMTP

Action Mailer is Rails’ email framework. A mailer class prepares the recipient, sender, subject, variables, and views. Rails then uses the configured delivery method to send the completed message.

For Rails SMTP email, the important configuration values are:

  • address: the SMTP relay hostname supplied by Volanea.
  • port: the submission port supplied by Volanea.
  • user_name: the SMTP username supplied for your credential.
  • password: your Volanea API key or SMTP password, loaded from an environment variable.
  • authentication: the authentication mechanism the relay expects.
  • enable_starttls_auto or tls: the encryption behavior required by the selected port.
  • domain: the hostname Rails presents in the SMTP EHLO command.

The sender visible to recipients is set by the mailer’s from header. It must be a sender identity that Volanea permits you to use. Your SMTP username is an authentication identity; it is not necessarily the address that should appear in the From header.

Rails can render both HTML and plain-text parts from matching templates. Sending both formats is a good default for transactional mail: capable mail clients use the HTML version, while other clients can display the text alternative. Rails packages those views as a multipart email automatically when both templates exist for the same mailer action.

Install the local environment dependency

Rails itself supplies Action Mailer, so you do not need a Volanea-specific SMTP gem. For local development, install dotenv-rails so a local .env file can provide credentials without placing them in Ruby source files.

Run this from the root of your Rails application:

bundle add dotenv-rails --group "development,test"

Then install the updated bundle:

bundle install

dotenv-rails is for local development and test convenience. In production, configure the same variables in your hosting provider, container runtime, CI secret store, or operating-system service configuration. Do not rely on a .env file being deployed, and do not commit one containing real secrets.

Add this entry to .gitignore if it is not already present:

.env

If your application already has a secure environment-variable workflow, you can skip the dependency installation and use that workflow instead. The Rails configuration below is unchanged because it reads from ENV.

Add Volanea SMTP credentials to your environment

Create a .env file in the project root for local development. Copy the SMTP server address, port, username, and TLS requirements from the Volanea credentials provided for your account. The API key is deliberately stored only in VOLANEA_API_KEY.

# Copy these connection values from your Volanea SMTP credentials.
VOLANEA_SMTP_ADDRESS=smtp.example.volanea-host
VOLANEA_SMTP_PORT=587
VOLANEA_SMTP_USERNAME=your-smtp-username
VOLANEA_SMTP_AUTHENTICATION=plain
VOLANEA_SMTP_ENCRYPTION=starttls

# Keep this secret out of source control.
VOLANEA_API_KEY=sk_your_volanea_api_key

# Use a configured sender domain and a recipient you control for testing.
MAILER_FROM="Example App <notifications@your-verified-domain.example>"
MAILER_TEST_TO=you@example.com
MAILER_EHLO_DOMAIN=your-app.example

Replace every example value before running the integration. In particular, do not guess the SMTP address or port. SMTP relays can support different submission ports and TLS modes, and a mismatch between port and encryption mode causes connection errors that look like authentication failures.

This guide supports the two common secure SMTP patterns:

  1. STARTTLS: the connection begins as SMTP and upgrades to TLS. Set VOLANEA_SMTP_ENCRYPTION=starttls.
  2. Implicit TLS: TLS starts immediately when the TCP connection opens. Set VOLANEA_SMTP_ENCRYPTION=implicit_tls.

Use the exact mode associated with the port shown in your Volanea SMTP credentials. Do not set both modes at once. A port expecting implicit TLS cannot complete a plaintext SMTP greeting before encryption, while a STARTTLS endpoint expects the opposite order.

The example names VOLANEA_API_KEY because many SMTP relay configurations use an API key as the password. If Volanea issued a dedicated SMTP password rather than an API key for your account, keep the configuration structure but store that credential in a separate secret such as VOLANEA_SMTP_PASSWORD and point the Rails configuration to it.

Configure Action Mailer for Volanea SMTP

Add the following configuration to the environment where you will send mail. For a local test, put it in config/environments/development.rb. For deployment, put the corresponding configuration in config/environments/production.rb.

# config/environments/development.rb

Rails.application.configure do
  # Other development configuration...

  config.action_mailer.delivery_method = :smtp
  config.action_mailer.perform_deliveries = true
  config.action_mailer.raise_delivery_errors = true

  # Set this to your application’s public host when emails contain URLs.
  config.action_mailer.default_url_options = {
    host: ENV.fetch("APP_HOST", "localhost"),
    protocol: ENV.fetch("APP_PROTOCOL", "http")
  }

  encryption = ENV.fetch("VOLANEA_SMTP_ENCRYPTION", "starttls")

  config.action_mailer.smtp_settings = {
    address: ENV.fetch("VOLANEA_SMTP_ADDRESS"),
    port: Integer(ENV.fetch("VOLANEA_SMTP_PORT")),
    domain: ENV.fetch("MAILER_EHLO_DOMAIN", "localhost"),
    user_name: ENV.fetch("VOLANEA_SMTP_USERNAME"),
    password: ENV.fetch("VOLANEA_API_KEY"),
    authentication: ENV.fetch("VOLANEA_SMTP_AUTHENTICATION", "plain").to_sym,
    enable_starttls_auto: encryption == "starttls",
    tls: encryption == "implicit_tls",
    open_timeout: 5,
    read_timeout: 5
  }
end

This code intentionally fails early when required values are missing. ENV.fetch("VOLANEA_SMTP_ADDRESS"), for example, raises a clear error during boot rather than silently attempting to deliver through a default local SMTP server. That behavior is useful in production because an application that falls back to an unintended mail server can lose transactional messages without an obvious exception.

The open_timeout limits how long Rails waits to establish the network connection. The read_timeout limits how long it waits for the relay’s response. These settings do not replace a background job strategy, but they prevent a blocked SMTP connection from tying up a web request indefinitely.

For production, change APP_HOST and APP_PROTOCOL to your real application hostname and HTTPS. Password-reset and account-confirmation URLs should never point to localhost in a deployed email.

Why the API key belongs in password

SMTP authentication has a username field and a password field. Your Volanea SMTP credential details determine the username. When Volanea instructs you to use an API key as the SMTP secret, pass that key as the SMTP password:

password: ENV.fetch("VOLANEA_API_KEY")

Do not put the key in a custom email header, the from address, or a Rails view. SMTP credentials are used only during relay authentication. The recipient never needs them, and a mailer template should never have access to them.

Create a complete transactional mailer

Generate a mailer from the Rails application root:

bin/rails generate mailer TransactionalMailer welcome

Replace the generated mailer with this implementation:

# app/mailers/transactional_mailer.rb
class TransactionalMailer < ApplicationMailer
  default from: ENV.fetch("MAILER_FROM")

  def welcome
    @name = params.fetch(:name)
    @login_url = params.fetch(:login_url)

    mail(
      to: params.fetch(:to),
      subject: "Welcome to Example App"
    )
  end
end

Add the HTML version of the message:

<%# app/views/transactional_mailer/welcome.html.erb %>
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Welcome to Example App</title>
  </head>
  <body>
    <h1>Welcome, <%= @name %>!</h1>

    <p>Your account is ready. You can sign in whenever you need to continue.</p>

    <p>
      <a href="<%= @login_url %>">Open Example App</a>
    </p>
  </body>
</html>

Add the plain-text alternative:

<%# app/views/transactional_mailer/welcome.text.erb %>
Welcome, <%= @name %>!

Your account is ready. Sign in here:
<%= @login_url %>

Finally, use this command to send one transactional email immediately:

bin/rails runner 'TransactionalMailer.with(
  to: ENV.fetch("MAILER_TEST_TO"),
  name: "Ada",
  login_url: "https://example.com/login"
).welcome.deliver_now'

This is the complete working flow: dotenv-rails loads local values, Rails reads SMTP settings from ENV, Action Mailer renders the two templates, and deliver_now submits the email through the configured Volanea relay.

When the command exits without an exception, check the destination inbox and the relay’s message activity. If it arrives in spam, do not treat that as a Rails rendering bug. Check the sender domain configuration, authentication alignment, recipient mailbox filtering, and message content separately.

The complete Rails SMTP email example in one place

Use the following file list as a copy-and-paste checklist. This is useful when you want to compare a working minimal integration against an existing application.

.env
config/environments/development.rb
app/mailers/transactional_mailer.rb
app/views/transactional_mailer/welcome.html.erb
app/views/transactional_mailer/welcome.text.erb

The key requirement is that the MAILER_FROM address belongs to a sender domain configured for your Volanea account. A valid SMTP login does not automatically authorize every possible From address. The relay can accept authentication while rejecting or suppressing a message whose sender identity is not permitted.

Keep the first message intentionally simple. Avoid attachments, inline images, complex layouts, user-supplied HTML, and large recipient lists until basic SMTP submission succeeds. A small welcome message makes it easier to identify whether a failure is caused by credentials, TLS, sender authorization, template rendering, or recipient delivery.

Sending from application code

In a controller, service object, model callback, or workflow, build the mailer with only the data needed to render the message:

TransactionalMailer.with(
  to: user.email,
  name: user.first_name,
  login_url: login_url
).welcome.deliver_now

For nonessential messages, or for messages triggered during a user-facing request, use Rails’ job system instead:

TransactionalMailer.with(
  to: user.email,
  name: user.first_name,
  login_url: login_url
).welcome.deliver_later

deliver_now is best for a controlled initial test and for cases where the application must know synchronously whether SMTP submission failed. deliver_later queues the mail delivery through Active Job. It improves request latency, but it only works when a queue adapter and worker process are actually running.

Do not use deliver_later for a password-reset flow unless you understand the operational tradeoff. It is usually appropriate, but the queue must be monitored because a stopped worker means the message has not even been submitted to SMTP yet.

Test the integration before production

A successful development test should cover more than “no Ruby exception occurred.” Test the email at three levels: message generation, SMTP submission, and received output.

Test rendering without contacting SMTP

A mailer test can verify recipient, sender, subject, and body without using network credentials:

# test/mailers/transactional_mailer_test.rb
require "test_helper"

class TransactionalMailerTest < ActionMailer::TestCase
  test "welcome renders both email formats" do
    email = TransactionalMailer.with(
      to: "recipient@example.com",
      name: "Ada",
      login_url: "https://example.com/login"
    ).welcome

    assert_equal ["recipient@example.com"], email.to
    assert_equal "Welcome to Example App", email.subject
    assert_includes email.html_part.body.to_s, "Welcome, Ada!"
    assert_includes email.text_part.body.to_s, "Welcome, Ada!"
  end
end

Run it with:

bin/rails test test/mailers/transactional_mailer_test.rb

This test catches missing templates, incorrect instance variables, malformed mailer calls, and accidental changes to content before a real send. It does not validate SMTP credentials or delivery.

Test SMTP submission with a controlled recipient

Use bin/rails runner and an inbox you own. Keep raise_delivery_errors enabled in the environment under test. With that setting, authentication, TLS negotiation, connection, and many relay errors are surfaced to the command instead of being swallowed by application logging.

A relay acceptance response means the relay accepted responsibility for processing the message. It does not guarantee final mailbox placement. Check spam, promotions, quarantine, or filtering rules before assuming the message was lost.

Verify both parts and links

Open the received email in a browser-based client and a mobile client if possible. Confirm that:

  • The displayed sender is your expected configured address.
  • The subject is correct and not duplicated.
  • The HTML version renders cleanly.
  • The plain-text part is readable when HTML is disabled.
  • The login link points to the correct HTTPS application hostname.
  • The recipient can reply if your workflow expects replies.

The Content-Type header should generally be produced by Rails from the templates. Do not manually force the full MIME structure unless you have a specific advanced use case. Rails is better positioned to build a correct multipart message when you provide matching .html.erb and .text.erb templates.

Common errors with Rails SMTP and Volanea

The following failures are common because SMTP setup crosses application configuration, secrets, network policy, TLS, sender authorization, and mail content.

Authentication failed or 535 credentials rejected

Authentication errors typically mean one of these values is wrong: SMTP username, API key, SMTP password, authentication mechanism, or target relay address. Confirm that the process running Rails has the expected variables, rather than only confirming that your terminal shell has them.

Start by printing only non-secret configuration during local debugging:

Rails.logger.info(
  smtp_address: ENV["VOLANEA_SMTP_ADDRESS"],
  smtp_port: ENV["VOLANEA_SMTP_PORT"],
  smtp_username_present: ENV["VOLANEA_SMTP_USERNAME"].present?,
  api_key_present: ENV["VOLANEA_API_KEY"].present?
)

Never log the API key itself. Check that the key was copied without whitespace, has not been revoked, and is the credential intended for SMTP authentication. Also verify VOLANEA_SMTP_AUTHENTICATION; a relay that expects one mechanism can reject a client configured for another.

Connection timeout, refused connection, or SocketError

These errors happen before authentication. Check the hostname and port against the Volanea SMTP credentials, then verify outbound SMTP is permitted from your development machine, container, or cloud network.

Cloud providers and corporate networks sometimes restrict outbound SMTP ports. A timeout is different from a rejected credential: Rails never reached the relay in the first place. Do not “fix” a timeout by changing the API key.

Keep open_timeout and read_timeout reasonably short so application requests do not hang. For production workloads, submit noncritical mail with deliver_later and monitor the queue, but still fix network reachability rather than endlessly retrying a blocked connection.

TLS handshake errors or wrong version number

TLS errors almost always indicate that the SMTP port and encryption mode do not match. If the configured port expects STARTTLS, use:

VOLANEA_SMTP_ENCRYPTION=starttls

If the configured port expects TLS immediately on connect, use:

VOLANEA_SMTP_ENCRYPTION=implicit_tls

Do not set enable_starttls_auto and tls to true together. In the sample, the encryption environment variable makes the modes mutually exclusive. Avoid disabling certificate verification as a workaround. A certificate error should lead to verification of the relay hostname, system clock, CA bundle, and network interception—not a permanent reduction in transport security.

Sender rejected, unauthorized sender, or message accepted but not delivered

The MAILER_FROM value must use a sender identity configured for your Volanea account. If your code says notifications@your-verified-domain.example, then that domain must be the sending domain you configured—not merely a domain you own.

Also distinguish between the visible From address and the relay login username. The SMTP username authenticates the submission; the visible sender identifies the message to the recipient. They can be different values.

If SMTP submission succeeds but delivery is not visible in the inbox, inspect Volanea message events and the recipient mailbox. Common causes include suppression rules, recipient filtering, an invalid recipient address, sender-domain misconfiguration, or a mailbox provider placing the email in spam.

Wrong content type, blank HTML, or an email that shows raw markup

Rails chooses email parts from the template files associated with a mailer action. For TransactionalMailer#welcome, use these names exactly:

app/views/transactional_mailer/welcome.html.erb
app/views/transactional_mailer/welcome.text.erb

A file with the wrong action name, directory, or extension might not be rendered as expected. Sending only an HTML template can work, but providing both HTML and text alternatives gives Rails a proper multipart message and improves compatibility.

Avoid setting content_type manually in the mailer just to force HTML. If the recipient sees raw tags, first confirm the HTML template has the .html.erb suffix and that you are not passing HTML as a text-only body from another code path.

deliver_later returns, but no email is sent

deliver_later does not send SMTP mail in the current request. It enqueues work for Active Job. If the queue adapter is configured incorrectly, the worker is stopped, the job fails, or the deployment has no worker process, the message will remain queued or fail before SMTP submission.

For the first integration test, use deliver_now so errors appear immediately in the terminal. Once SMTP works, switch to deliver_later where asynchronous delivery is appropriate and monitor failed jobs.

Async/await mistakes from copied JavaScript examples

Rails mailers do not use JavaScript async or await. A common integration mistake is copying a Node.js or REST API example into a Rails code path and expecting await-style behavior. In Rails, the immediate call is deliver_now; the queued alternative is deliver_later.

Do not wrap a mailer call in arbitrary threads to imitate asynchronous behavior. Use Active Job and your chosen queue backend. That preserves retries, observability, job serialization, and deployment-friendly worker execution.

Missing environment variable errors

The sample uses ENV.fetch intentionally. An error such as key not found: "VOLANEA_API_KEY" is a deployment configuration problem, not an SMTP problem.

Check the environment of the actual running process. A variable in your local shell may not be present in a Docker container, background worker, release process, systemd service, CI job, or production web process. Restart the affected process after changing secrets if your runtime only reads environment variables at boot.

Production guidance for transactional email

Once the sample works, move the configuration into config/environments/production.rb and set the secrets in production. Do not make production mail behavior depend on development defaults.

Use a stable sender address such as notifications@your-domain.example for application notifications and a separately monitored support or reply address when replies are expected. Consistency helps users recognize your messages and makes sender behavior easier to audit.

Keep email sending separate from the database transaction that triggers it. For example, create a user record first, then enqueue the welcome email after the transaction commits. Otherwise a job can send a welcome message for a record that later rolls back.

For sensitive flows such as password resets, avoid logging full reset URLs, full recipient addresses, and message bodies. Logs often have broader access and longer retention than the application database. Store only the diagnostic data necessary to identify a failed workflow.

If you need to estimate service costs before production volume grows, review transactional email pricing alongside your expected message count, retry strategy, and campaign workload. SMTP itself is simple, but operational volume includes notifications, retries, password-reset requests, receipts, and system alerts—not only the messages your product team explicitly designs.

Next steps: webhooks, templates, and delivery operations

After you can submit a basic message, build the operational pieces that make email reliable at scale.

Webhooks let your application receive delivery-related events and react to them. Use them to update internal message status, detect bounces, record complaints, avoid repeatedly sending to failed recipients, and investigate support requests. Webhook handlers should validate incoming requests, return quickly, persist an event identifier, and be idempotent because providers can retry delivery.

Templates let you reuse approved layouts and message structures while changing recipient-specific data. Whether you continue rendering Rails views or introduce provider-managed templates, treat template changes like application changes: preview them, test rendering with representative data, verify links, and include both readable copy and a plain-text fallback where applicable.

For the REST API reference and setup material that complement this SMTP integration, see the email API reference and setup guides. SMTP is a strong fit for existing Action Mailer applications; an API workflow can be useful when you need request-level controls, provider-managed templates, or a non-Rails service to send the same message types.

FAQ

Do I need a Volanea Ruby gem for Rails SMTP email?

No. Rails Action Mailer supports SMTP directly, so the SMTP integration uses config.action_mailer.smtp_settings. The only optional dependency in this guide is dotenv-rails for local environment-variable loading.

Should I use deliver_now or deliver_later?

Use deliver_now for an initial SMTP test and for workflows that must synchronously know whether submission failed. Use deliver_later for most production notifications when an Active Job queue and worker are configured and monitored.

Is VOLANEA_API_KEY the same as the visible sender address?

No. The API key is a secret used for SMTP authentication when Volanea instructs you to use it as the password. The visible sender is the MAILER_FROM address and must use a sender identity configured for your Volanea account.

Why does my Rails mailer work locally but fail in production?

Production failures are usually missing secrets, blocked outbound SMTP, an incorrect SMTP host or TLS mode, a non-running background worker, or a sender domain that is not configured in the production Volanea account. Check the environment of the deployed web or worker process rather than only your local .env file.

Can I send HTML and plain text in the same message?

Yes. Create matching welcome.html.erb and welcome.text.erb templates for the same mailer action. Rails builds a multipart email so clients can choose the appropriate version.