Project

inbox_beam

0.0
The project is in a healthy, maintained state
InboxBeam appends a message straight into your own mailbox using the IMAP APPEND command instead of sending email. Useful for landing app notifications, contact-form copies, and cron alerts in your own inbox without standing up a sending domain. Includes a drop-in Action Mailer delivery method.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Runtime

~> 0.2
 Project Readme

inbox_beam

Gem Version license

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.

Install

# Gemfile
gem "inbox_beam"
bundle install
# or
gem install inbox_beam

Ruby >= 2.7.

Rails / Action Mailer

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.

1. Configure the delivery method

# 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.

2. Write a mailer (or use one you already have)

# 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>

3. Deliver it

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.

Per-environment tip

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.

Plain Ruby

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")

This is not email delivery

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.

Gmail setup

  1. Enable IMAP in Gmail settings.
  2. Turn on 2-Step Verification and create an App Password.
  3. 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.

API

InboxBeam::Client.new(...)

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.

client.beam(...)

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).

InboxBeam::Message.build(...)

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")

How it works

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.

License

MIT