Send notification emails to your own inbox from Ruby and Rails without SMTP, a sending domain, or SPF/DKIM/DMARC setup.
If all you want is for your Rails app to drop a contact-form copy, a sign-up alert, or a cron failure into your own inbox, configuring SMTP, a sending domain, SPF, DKIM, DMARC, and a provider like SES, SendGrid, or Postmark is a lot of deliverability overhead for mail only you will read.
inbox_beam skips all of it. It uses the IMAP APPEND command to write the
message straight into your mailbox. No SMTP, no sending domain, no
deliverability — the email shows up unread and searchable, and nothing was sent.
It ships as a plain Ruby client and as a drop-in Action Mailer delivery method, so your existing Rails mailers can land in your inbox unchanged.
# Gemfile
gem "inbox_beam"bundle install
# or
gem install inbox_beamRuby >= 2.7.
The delivery method is registered automatically when the gem loads. Point Action Mailer at it, and every mailer you already have appends to your inbox instead of sending over SMTP — no other code changes.
# config/environments/production.rb
config.action_mailer.delivery_method = :inbox_beam
config.action_mailer.inbox_beam_settings = {
host: "imap.gmail.com",
auth: { user: "you@example.com", pass: ENV["IMAP_APP_PASSWORD"] },
mailbox: "INBOX" # optional, defaults to "INBOX"
}Keep secrets out of source. With Rails encrypted credentials:
config.action_mailer.inbox_beam_settings = {
host: "imap.gmail.com",
auth: {
user: Rails.application.credentials.dig(:imap, :user),
pass: Rails.application.credentials.dig(:imap, :app_password)
}
}inbox_beam_settings accepts:
| Key | Default | Notes |
|---|---|---|
host: |
— | IMAP host, e.g. imap.gmail.com. Required. |
auth: |
— | { user:, pass: } (app password) or { user:, access_token: } (OAuth2). Required. |
port: |
993 |
|
ssl: |
true |
Use TLS. |
mailbox: |
"INBOX" |
Target mailbox or label. |
unread: |
true |
Leave the appended message unread. |
The mailer's own mail(from:, to:, subject:) supplies the headers and body, so
the rendered message lands in your inbox exactly as Action Mailer built it.
# app/mailers/notification_mailer.rb
class NotificationMailer < ApplicationMailer
def contact_form(submission)
@submission = submission
mail(
to: "you@example.com",
subject: "[Contact] #{submission.name}"
)
end
end<%# app/views/notification_mailer/contact_form.html.erb %>
<h1>New contact-form submission</h1>
<p><strong>From:</strong> <%= @submission.name %> (<%= @submission.email %>)</p>
<p><%= @submission.message %></p>NotificationMailer.contact_form(submission).deliver_later
# → appended to your inbox, unread and searchable. No SMTP, no SPF/DKIM/DMARC.That's the whole integration — deliver_now / deliver_later work as usual, and
nothing is sent over the wire to another server.
Use :inbox_beam only where you want notifications to reach your own inbox
(production, staging). Leave :test in the test environment and :letter_opener
or :file in development as you normally would.
require "inbox_beam"
beam = InboxBeam::Client.new(
host: "imap.gmail.com",
auth: { user: "you@example.com", pass: ENV["IMAP_APP_PASSWORD"] }
)
beam.beam(subject: "New contact", text: "someone submitted the form")HTML plus text produces a multipart/alternative message:
beam.beam(
subject: "Weekly report",
text: "Signups: 42",
html: "<h1>Weekly report</h1><p>Signups: 42</p>"
)Override the target mailbox per call:
beam.beam(subject: "Cron failed", text: "nightly-export exited 1", mailbox: "Alerts")inbox_beam appends to a mailbox you already control. It does not send mail and cannot reach anyone else. To email a user or customer, use SMTP or a delivery API. It keeps no send log and the date is set by the client, so don't use it where an audit trail matters. It's for your own notifications.
- Enable IMAP in Gmail settings.
- Turn on 2-Step Verification and create an App Password.
- Use it as
auth[:pass].
Workspace admins can disable app passwords. In that case pass an OAuth2 token as
auth[:access_token] instead of pass (the client authenticates with XOAUTH2).
A dedicated notify@ account that forwards to you is safer than your primary
account's credentials on a server.
| Option | Default | Notes |
|---|---|---|
host: |
— | IMAP host, e.g. imap.gmail.com. |
auth: |
— | { user:, pass: } (app password) or { user:, access_token: } (OAuth2). |
port: |
993 |
|
ssl: |
true |
Use TLS. |
mailbox: |
"INBOX" |
Target mailbox or label. |
from: |
auth[:user] |
Default From. |
to: |
auth[:user] |
Default To. |
unread: |
true |
Leave appended messages unread. |
subject_prefix: |
nil |
Prepended to every subject. |
Keyword args: subject: (required), text:, html:, from:, to:,
mailbox:, unread:, date:. Per-call values override the constructor
defaults. Returns an InboxBeam::Result with mailbox, uid, and
uid_validity (uid comes from the server's APPENDUID response).
The RFC 5322 builder is available on its own if you want the raw message without the IMAP connection. Zero dependencies, UTF-8 safe.
raw = InboxBeam::Message.build(from: "a@x.com", to: "b@x.com", subject: "Hi", text: "Body")IMAP's APPEND command (RFC 9051 §6.3.12) adds a message to the end of a
mailbox. It's the same command mail clients use to save sent copies and drafts.
inbox_beam builds an RFC 5322 message and appends it over a TLS IMAP connection
using Ruby's standard net/imap — no runtime dependencies of its own.
A TypeScript/Node version is at inbox-beam.
MIT