Missive
A lightweight Rails toolkit for building newsletter features. Missive provides the primitives for managing newsletters and subscribers, with Postmark handling delivery.
Overview
Features
- Newsletter Management: Create and organize newsletters within your Rails application
- Postmark Integration: Leverage Postmark's reliable email delivery service
- Rails Native: Designed to work seamlessly with Rails conventions and ActionMailer
- Subscriber Management: Handle your newsletter subscriber lists
Scope
Goals
- Rely on Postmark as much as possible, integrate with webhooks, send through Postmark API (not SMTP).
- Provide a way to compose messages that include content from the host app models.
Non-goals
- Integrate with other sending services.
- Send transactional emails or email sequences: Missive focuses on newsletters.
- Provide ready-made subscription forms: subscription management is the responsibility of the host app.
- Multi-tenancy: Missive is designed for a single Rails app and domain.
Concepts
Models
-
Senderis an identity used to send messages, optionally associated with aUserfrom the host app. It has a corresponding Sender Signature in Postmark. -
Subscriberis a person who have opted in to receiving emails or have been added manually, optionally associated with aUserfrom the host app. -
Subscriptionis the relation between a subscriber and a list. -
Listis a list of subscribers. It uses a specific Message Stream to send messages through Postmark. -
Messageis an email sent to subscribers of a given list. -
Dispatchis the relation between a subscriber and a message (ie. when aMessageis sent, it's dispatched to all subscribers). It's called Email in Postmark.
Requirements
- Rails 8.0 or higher
- A Postmark account with API credentials
Dependencies
- Official postmark gem
-
time_for_a_boolean to back boolean concepts (
sent,delivered,open, ...) with timestamps - rails-pattern_matching to use pattern matching when processing incoming webhooks
Usage
Setup
bundle add missiveInstall the migrations:
rails generate missive:installConfiguration
Missive uses the same configuration as postmark-rails. Please follow the postmark-rails configuration instructions to set up your Postmark API credentials.
Quick start
Connect the host app User model (optional)
The host app User can be associated to a Missive::Subscriber and/or a Missive::Sender, using the Missive::User concern.
class User < ApplicationRecord
include Missive::User
endThe concerns can also be included separately, which is useful if User needs to be implemented as a Sender or Subscriber only.
class User < ApplicationRecord
include Missive::UserAsSender
include Missive::UserAsSubscriber
endThis is equivalent to:
class User < ApplicationRecord
# Missive::UserAsSender
has_one :sender # ...
has_many :sent_dispatches # ...
has_many :sent_lists # ...
has_many :sent_messages # ...
def init_sender(attributes = {});
# ...
end
# Missive::UserAsSubscriber
has_one :subscriber # ...
has_many :dispatches # ...
has_many :subscriptions # ...
has_many :subscribed_lists # ...
has_many :unsubscribed_lists # ...
def init_subscriber(attributes = {})
# ...
end
endManage subscriptions
user = User.first
list = Missive::List.first
# Make sure the User has an associated Missive::Subscriber:
# - if one exists with the same email, associate it
# - else create a new subscriber with the same email
user.init_subscriber
# List the subscriptions
user.subscriptions # returns a `Missive::Subscription` collection
# List the (un)subscribed lists
user.subscribed_lists # returns a `Missive::List` collection
user.unsubscribed_lists # returns a `Missive::List` collection
# Subscribe to an existing Missive::List
user.subscriber.subscriptions.create!(list:)
# Unsubscribe from the list
user.subscriptions.find_by(list:).suppress!(reason: :manual_suppression)Manage senders
user = User.where(admin: true).first
list = Missive::List.first
# Make sure the User has an associated Missive::Sender:
# - if one exists with the same email, associate it
# - else create a new sender with the same email
# then assign them the provided name
user.init_sender(name: user.full_name)
# Make them the default sender for a list
user.sent_lists << listManage lists
# Create a new list
list = Missive::List.create!(name: "My newsletter")
# Choose a specific Message Stream to send messages for this list
list.update!(postmark_message_stream_id: "bulk")
# Get available lists
Missive::List.all
# Get list stats
list.subscriptions_count # how many people subscribe or unsubscribe to this list?
list.messages_count # how many messages have been created in this list?Warning
Everything below is currently being developed and is not yet ready for use.
Manage messages
# Create a new message in a list
list.create_message!(subject: "Hello world!")
# TODO: add message content
# Send the message to the list
message.send!Sending with Postmark Bulk API
Missive leverages the Bulk Email API endpoints.
Warning
This endpoint is available to early access customers only. You need to request access. Learn more
The official postmark gem does not support these endpoints yet, so Missive ships with Stamp, a thin layer over Postmark's official library.
Sending a message in bulk
You can pass a Hash that matches the body expected by the API.
Missive::Stamp::ApiClient.deliver_in_bulk(
from: "sender@example.com",
subject: "Hello {{name}}",
html_body: "<p>Hello {{name}}</p>",
text_body: "Hello {{name}}",
messages: [
{
to: "jane.doe@example.com",
template_model: {name: "Jane"}
},
{
to: "john.doe@example.com",
template_model: {name: "John"}
}
]
)You can also pass a Mail instance and an Array of recipients.
mail = Mail.new do
from "sender@example.com"
subject "Hello {{name}}"
body: "Hello {{name}}"
end
Missive::Stamp::ApiClient.deliver_message_in_bulk(
mail,
[
{
to: "jane.doe@example.com",
template_model: {name: "Jane"}
},
{
to: "john.doe@example.com",
template_model: {name: "John"}
}
]
)Getting the status of a bulk API request
Missive::Stamp::ApiClient.get_bulk_status("f24af63c-533d-4b7a-ad65-4a7b3202d3a7")License
The gem is available as open source under the terms of the MIT License.
Code of Conduct
Everyone interacting in the Missive project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.