### Setup Mailkick Development Environment Source: https://github.com/ankane/mailkick/blob/master/README.md Clone the repository, install dependencies with Bundler, and run tests using Rake. This is the standard procedure for setting up the Mailkick development environment. ```sh git clone https://github.com/ankane/mailkick.git cd mailkick bundle install bundle exec rake test ``` -------------------------------- ### Install Mailkick Gem and Run Migrations Source: https://context7.com/ankane/mailkick/llms.txt Add the Mailkick gem to your Gemfile, install it, and then generate and run the migration to create the necessary database table. ```ruby gem "mailkick" ``` ```sh bundle install rails generate mailkick:install rails db:migrate ``` -------------------------------- ### Generate and Migrate Mailkick Install Source: https://github.com/ankane/mailkick/blob/master/README.md Run the Mailkick generator and migrate your database to set up the necessary tables for subscription management. ```sh bundle install rails generate mailkick:install rails db:migrate ``` -------------------------------- ### Install Mailkick Gem Source: https://github.com/ankane/mailkick/blob/master/README.md Add the Mailkick gem to your Gemfile to begin using its features. ```ruby gem "mailkick" ``` -------------------------------- ### Using `has_subscriptions` Model Mixin (Default) Source: https://context7.com/ankane/mailkick/llms.txt Integrate subscription management into an ActiveRecord model. This default setup provides `subscribe`, `unsubscribe`, `subscribed?` instance methods and a `subscribed` class scope without any prefix. ```ruby # Default (no prefix) — methods: subscribe, unsubscribe, subscribed?, User.subscribed(list) class User < ApplicationRecord has_subscriptions end ``` -------------------------------- ### Configure Mailkick Opt-Out Processing Source: https://github.com/ankane/mailkick/blob/master/README.md Define a lambda method for `Mailkick.process_opt_outs_method` to handle opt-out data fetched from email services. This example shows how to process bounces and spam reports by destroying relevant subscriptions. ```ruby Mailkick.process_opt_outs_method = lambda do |opt_outs| emails = opt_outs.map { |v| v[:email] } subscribers = User.includes(:mailkick_subscriptions).where(email: emails).index_by(&:email) opt_outs.each do |opt_out| subscriber = subscribers[opt_out[:email]] next unless subscriber subscriber.mailkick_subscriptions.each do |subscription| subscription.destroy if subscription.created_at < opt_out[:time] end end end ``` -------------------------------- ### Customize Mailkick Subscription Status View Source: https://context7.com/ankane/mailkick/llms.txt Example of a customized `show.html.erb` view for the Mailkick subscription status page, allowing users to unsubscribe or resubscribe. ```erb <%# app/views/mailkick/subscriptions/show.html.erb (after running views generator) %>
<% if !subscribed? %>

You are unsubscribed.

<%= link_to "Resubscribe", subscribe_url %>

<% else %>

You are subscribed.

<%= link_to "Unsubscribe", unsubscribe_url %>

<% end %>
``` -------------------------------- ### Get Users Subscribed to a List Source: https://github.com/ankane/mailkick/blob/master/README.md Retrieve all users subscribed to a specific list using the `subscribed` class method. This is useful for sending emails. ```ruby User.subscribed("sales") ``` -------------------------------- ### Using `has_subscriptions` Model Mixin (Prefixed) Source: https://context7.com/ankane/mailkick/llms.txt Integrate subscription management into an ActiveRecord model with prefixed methods to avoid name collisions. This setup provides `mailkick_subscribe`, `mailkick_unsubscribe`, `mailkick_subscribed?` instance methods and a `mailkick_subscribed` class scope. ```ruby # Prefixed — methods: mailkick_subscribe, mailkick_unsubscribe, # mailkick_subscribed?, Admin.mailkick_subscribed(list) class Admin < ApplicationRecord has_subscriptions prefix: true end ``` -------------------------------- ### Prefixed Instance and Class Methods Source: https://context7.com/ankane/mailkick/llms.txt Demonstrates the usage of prefixed subscription methods for models configured with `prefix: true`. This ensures method names do not collide with other parts of your application. ```ruby # ---- Prefixed variant ---- admin = Admin.find(1) admin.mailkick_subscribe("alerts") admin.mailkick_subscribed?("alerts") # => true Admin.mailkick_subscribed("alerts") # => ActiveRecord::Relation admin.mailkick_unsubscribe("alerts") ``` -------------------------------- ### Instance Methods for Subscription Management Source: https://context7.com/ankane/mailkick/llms.txt Manage individual user subscriptions using `subscribe`, `subscribed?`, and `unsubscribe` methods. These methods are idempotent and handle record creation or deletion accordingly. ```ruby # ---- Instance methods ---- user = User.find(42) user.subscribe("newsletter") # => nil (idempotent, uses first_or_create!) user.subscribed?("newsletter") # => true user.subscribe("newsletter") # no-op, no duplicate record created user.unsubscribe("newsletter") # => nil (deletes the record, no error if absent) user.subscribed?("newsletter") # => false ``` -------------------------------- ### Mailkick.discover_services Source: https://context7.com/ankane/mailkick/llms.txt Called automatically by the Rails engine on boot. Iterates over all `Mailkick::Service` subclasses and instantiates any whose `discoverable?` class method returns `true`. You rarely need to call this manually. ```APIDOC ## `Mailkick.discover_services` — Automatic ESP Discovery Called automatically by the Rails engine on boot. Iterates over all `Mailkick::Service` subclasses and instantiates any whose `discoverable?` class method returns `true` (i.e., the matching gem is loaded and the environment variable is set). You rarely need to call this manually. ```ruby # Triggered automatically in config/initializers via the Engine: # Mailkick.discover_services unless Mailkick.services.any? # Manually force re-discovery (e.g., in tests or after credential change): Mailkick.services = [] Mailkick.discover_services # => nil # Mailkick.services now contains auto-detected service instances # Check which services were discovered: puts Mailkick.services.map(&:class) # => [Mailkick::Service::SendGrid] (if SENDGRID_API_KEY is set and gem is present) ``` ``` -------------------------------- ### Manual Mailkick Service Configuration Source: https://context7.com/ankane/mailkick/llms.txt Explicitly configure Mailkick's ESP clients using `Mailkick.services`. This allows for custom credentials, API keys, and specific options like `stream_id` or `domain` for each service. ```ruby # config/initializers/mailkick.rb # SendGrid — requires gem "sendgrid-ruby" and SENDGRID_API_KEY env var Mailkick.services = [ Mailkick::Service::SendGrid.new(api_key: ENV["SENDGRID_API_KEY"]) ] ``` ```ruby # Multiple services at once Mailkick.services = [ Mailkick::Service::SendGrid.new(api_key: ENV["SENDGRID_API_KEY"]), Mailkick::Service::Mailchimp.new( api_key: ENV["MAILCHIMP_API_KEY"], list_id: ENV["MAILCHIMP_LIST_ID"] ) ] ``` ```ruby # Postmark with non-default stream Mailkick.services = [ Mailkick::Service::Postmark.new( api_key: ENV["POSTMARK_API_KEY"], stream_id: "outbound" # default is "broadcast" ) ] ``` ```ruby # Mailgun with explicit domain Mailkick.services = [ Mailkick::Service::Mailgun.new( api_key: ENV["MAILGUN_API_KEY"], domain: "mg.example.com" ) ] ``` ```ruby # AWS SES — uses aws-sdk-sesv2 and standard AWS credential chain (no explicit key) Mailkick.services = [ Mailkick::Service::AwsSes.new ] ``` ```ruby # Mandrill Mailkick.services = [ Mailkick::Service::Mandrill.new(api_key: ENV["MANDRILL_API_KEY"]) ] ``` -------------------------------- ### Configure Postmark Service Stream Source: https://github.com/ankane/mailkick/blob/master/README.md If fetching suppressions from Postmark, use this initializer to change the default stream from 'broadcast' to 'outbound' by specifying the stream_id. Requires an API key. ```ruby Mailkick.services = [Mailkick::Service::Postmark.new(api_key: api_key, stream_id: "outbound")] ``` -------------------------------- ### Subscribe User to a List Source: https://github.com/ankane/mailkick/blob/master/README.md Use the `subscribe` method on a user instance to add them to a specific mailing list. ```ruby user.subscribe("sales") ``` -------------------------------- ### Restore Unsubscribe Link Support Source: https://github.com/ankane/mailkick/blob/master/README.md Use this initializer to restore support for unsubscribe links created before version 1.1.1 by rotating the previous secret token. Ensure the previous secret token is correctly determined. ```ruby Mailkick.message_verifier.rotate(previous_secret_token, serializer: Marshal) ``` -------------------------------- ### Manually Configure Mailkick Services Source: https://github.com/ankane/mailkick/blob/master/README.md For advanced control, manually configure the Mailkick services by providing instances with their respective API keys and list IDs. ```ruby Mailkick.services = [ Mailkick::Service::SendGrid.new(api_key: "API_KEY"), Mailkick::Service::Mailchimp.new(api_key: "API_KEY", list_id: "LIST_ID") ] ``` -------------------------------- ### Mailkick.services Source: https://context7.com/ankane/mailkick/llms.txt Override automatic service discovery and configure ESP clients explicitly with specific credentials or options. ```APIDOC ## `Mailkick.services` — Manual Service Configuration Override automatic service discovery and configure ESP clients explicitly with specific credentials or options. ```ruby # config/initializers/mailkick.rb # SendGrid — requires gem "sendgrid-ruby" and SENDGRID_API_KEY env var Mailkick.services = [ Mailkick::Service::SendGrid.new(api_key: ENV["SENDGRID_API_KEY"]) ] # Multiple services at once Mailkick.services = [ Mailkick::Service::SendGrid.new(api_key: ENV["SENDGRID_API_KEY"]), Mailkick::Service::Mailchimp.new( api_key: ENV["MAILCHIMP_API_KEY"], list_id: ENV["MAILCHIMP_LIST_ID"] ) ] # Postmark with non-default stream Mailkick.services = [ Mailkick::Service::Postmark.new( api_key: ENV["POSTMARK_API_KEY"], stream_id: "outbound" # default is "broadcast" ) ] # Mailgun with explicit domain Mailkick.services = [ Mailkick::Service::Mailgun.new( api_key: ENV["MAILGUN_API_KEY"], domain: "mg.example.com" ) ] # AWS SES — uses aws-sdk-sesv2 and standard AWS credential chain (no explicit key) Mailkick.services = [ Mailkick::Service::AwsSes.new ] # Mandrill Mailkick.services = [ Mailkick::Service::Mandrill.new(api_key: ENV["MANDRILL_API_KEY"]) ] ``` ``` -------------------------------- ### Add SendGrid Gem for Mailkick Source: https://github.com/ankane/mailkick/blob/master/README.md Include the `sendgrid-ruby` gem in your Gemfile if you are using SendGrid for fetching opt-outs. ```ruby gem "sendgrid-ruby" ``` -------------------------------- ### Mailkick.fetch_opt_outs Source: https://context7.com/ankane/mailkick/llms.txt Iterates over every configured service and calls `process_opt_outs_method` with the combined opt-out records. Typically invoked from a scheduled job. ```APIDOC ## `Mailkick.fetch_opt_outs` — Fetch Suppressions from ESPs Iterates over every configured service and calls `process_opt_outs_method` with the combined opt-out records. Typically invoked from a scheduled job. ```ruby # app/jobs/sync_opt_outs_job.rb class SyncOptOutsJob < ApplicationJob queue_as :default def perform Mailkick.fetch_opt_outs # => nil on success; raises on HTTP/API errors end end # Schedule with e.g. Sidekiq-Cron or Whenever: # SyncOptOutsJob.perform_later # every 1.hour, "Sync email opt-outs" (Whenever) ``` ``` -------------------------------- ### Prefix Mailkick Methods with `mailkick_` Source: https://github.com/ankane/mailkick/blob/master/README.md Configure Mailkick to prefix its generated methods with `mailkick_` by setting `prefix: true` in the `has_subscriptions` macro. ```ruby class User < ApplicationRecord has_subscriptions prefix: true end ``` -------------------------------- ### Add AWS SES Gem for Mailkick Source: https://github.com/ankane/mailkick/blob/master/README.md Include the `aws-sdk-sesv2` gem in your Gemfile if you are using AWS SES for fetching opt-outs. ```ruby gem "aws-sdk-sesv2" ``` -------------------------------- ### Add Postmark Gem for Mailkick Source: https://github.com/ankane/mailkick/blob/master/README.md Include the `postmark` gem in your Gemfile if you are using Postmark for fetching opt-outs. ```ruby gem "postmark" ``` -------------------------------- ### Generate Mailkick Web UI Views Source: https://context7.com/ankane/mailkick/llms.txt Run this generator to copy the Mailkick unsubscribe/resubscribe UI views into your application for customization. ```sh # Mount path is /mailkick by default (set Mailkick.mount = false to disable) # Routes provided by the engine: # GET /mailkick/subscriptions/:id → show subscription status page # GET /mailkick/subscriptions/:id/unsubscribe → unsubscribe (browser flow) # POST /mailkick/subscriptions/:id/unsubscribe → one-click unsubscribe (RFC 8058) # GET /mailkick/subscriptions/:id/subscribe → resubscribe # Customize the view: rails generate mailkick:views # Creates: app/views/mailkick/subscriptions/show.html.erb ``` -------------------------------- ### Enable Unsubscribe Headers Source: https://github.com/ankane/mailkick/blob/master/README.md Configure Mailkick to automatically add one-click unsubscribe headers to emails by setting `Mailkick.headers = true` in an initializer. ```ruby Mailkick.headers = true ``` -------------------------------- ### Access Mailkick Subscription Model Source: https://github.com/ankane/mailkick/blob/master/README.md You can directly access and query the `Mailkick::Subscription` model to manage subscriptions. ```ruby Mailkick::Subscription.all ``` -------------------------------- ### Fetch Opt-Outs from Email Services Source: https://github.com/ankane/mailkick/blob/master/README.md Call `Mailkick.fetch_opt_outs` to retrieve bounces, spam reports, and unsubscribes from configured email services. ```ruby Mailkick.fetch_opt_outs ``` -------------------------------- ### Enable RFC 8058 One-Click Unsubscribe Headers Source: https://context7.com/ankane/mailkick/llms.txt Configure Mailkick to automatically include `List-Unsubscribe` and `List-Unsubscribe-Post` headers in outgoing emails by setting `Mailkick.headers = true` in an initializer. ```ruby # config/initializers/mailkick.rb Mailkick.headers = true ``` -------------------------------- ### Processing Opt-Outs with Mailkick Source: https://context7.com/ankane/mailkick/llms.txt Configure `Mailkick.process_opt_outs_method` to handle opt-out records fetched from your ESP. This lambda should update your subscription records based on the provided email, time, and reason. ```ruby # config/initializers/mailkick.rb Mailkick.process_opt_outs_method = lambda do |opt_outs| # opt_outs is an Array of: # { email: "alice@example.com", time: Time, reason: "bounce"|"spam"|"unsubscribe" } emails = opt_outs.map { |v| v[:email] } subscribers = User .includes(:mailkick_subscriptions) .where(email: emails) .index_by(&:email) opt_outs.each do |opt_out| subscriber = subscribers[opt_out[:email]] next unless subscriber # Only remove subscriptions that were created BEFORE the opt-out event subscriber.mailkick_subscriptions.each do |subscription| subscription.destroy if subscription.created_at < opt_out[:time] end end end ``` -------------------------------- ### Generate Mailkick Views Source: https://github.com/ankane/mailkick/blob/master/README.md Run this command to copy Mailkick's default unsubscribe view into your application for customization. ```sh rails generate mailkick:views ``` -------------------------------- ### Add has_subscriptions to User Model Source: https://github.com/ankane/mailkick/blob/master/README.md Include the `has_subscriptions` macro in your User model to enable subscription functionality. ```ruby class User < ApplicationRecord has_subscriptions end ``` -------------------------------- ### Mailkick Subscription Table Migration Schema Source: https://context7.com/ankane/mailkick/llms.txt This is the schema for the `mailkick_subscriptions` table generated by the Mailkick migration. It includes polymorphic references for subscribers and a unique index for subscriber and list combinations. ```ruby # db/migrate/YYYYMMDDHHMMSS_mailkick_install.rb class MailkickInstall < ActiveRecord::Migration[8.0] def change create_table :mailkick_subscriptions do |t| t.references :subscriber, polymorphic: true, index: false t.string :list t.timestamps end add_index :mailkick_subscriptions, [:subscriber_type, :subscriber_id, :list], unique: true, name: "index_mailkick_subscriptions_on_subscriber_and_list" end end ``` -------------------------------- ### Automatic Mailkick Service Discovery Source: https://context7.com/ankane/mailkick/llms.txt Mailkick automatically discovers and instantiates services based on loaded gems and environment variables. You can manually trigger re-discovery or inspect the discovered services. ```ruby # Triggered automatically in config/initializers via the Engine: # Mailkick.discover_services unless Mailkick.services.any? # Manually force re-discovery (e.g., in tests or after credential change): Mailkick.services = [] Mailkick.discover_services # => nil # Mailkick.services now contains auto-detected service instances # Check which services were discovered: puts Mailkick.services.map(&:class) # => [Mailkick::Service::SendGrid] (if SENDGRID_API_KEY is set and gem is present) ``` -------------------------------- ### Mailkick.process_opt_outs_method Source: https://context7.com/ankane/mailkick/llms.txt A lambda that Mailkick calls with an array of opt-out hashes. This method is used to wire opt-outs into your subscription records. ```APIDOC ## `Mailkick.process_opt_outs_method` — Opt-Out Callback A required lambda that Mailkick calls with an array of opt-out hashes (`{ email:, time:, reason: }`) after fetching suppressions from your ESP. Define it in an initializer to wire opt-outs into your subscription records. ```ruby # config/initializers/mailkick.rb Mailkick.process_opt_outs_method = lambda do |opt_outs| # opt_outs is an Array of: # { email: "alice@example.com", time: Time, reason: "bounce"|"spam"|"unsubscribe" } emails = opt_outs.map { |v| v[:email] } subscribers = User .includes(:mailkick_subscriptions) .where(email: emails) .index_by(&:email) opt_outs.each do |opt_out| subscriber = subscribers[opt_out[:email]] next unless subscriber # Only remove subscriptions that were created BEFORE the opt-out event subscriber.mailkick_subscriptions.each do |subscription| subscription.destroy if subscription.created_at < opt_out[:time] end end end ``` ``` -------------------------------- ### Add Mailgun Gem for Mailkick Source: https://github.com/ankane/mailkick/blob/master/README.md Include the `mailgun-ruby` gem in your Gemfile if you are using Mailgun for fetching opt-outs. ```ruby gem "mailgun-ruby" ``` -------------------------------- ### Generating Mailkick Subscription Tokens Source: https://context7.com/ankane/mailkick/llms.txt Use `Mailkick.generate_token` to create signed tokens for unsubscribe URLs. This method is used internally by `mailkick_unsubscribe_url` but can be used for custom URL construction. It requires a subscriber object and a list name. ```ruby user = User.find(99) token = Mailkick.generate_token(user, "newsletter") # => "eyJfcmFpbHMiOnsibWVzc..." (a JSON MessageVerifier-signed string) # Build a raw URL without ActionMailer context: url = Rails.application.routes.url_helpers.url_for( controller: "mailkick/subscriptions", action: "unsubscribe", id: token, host: "example.com" ) # => "https://example.com/mailkick/subscriptions/TOKEN/unsubscribe" # Error handling: Mailkick.generate_token(nil, "newsletter") # raises ArgumentError: Missing subscriber Mailkick.generate_token(user, "") # raises ArgumentError: Missing list ``` -------------------------------- ### Add Mandrill Gem for Mailkick Source: https://github.com/ankane/mailkick/blob/master/README.md Include the `mandrill-api` gem in your Gemfile if you are using Mandrill for fetching opt-outs. ```ruby gem "mandrill-api" ``` -------------------------------- ### Add Gibbon Gem for Mailchimp Source: https://github.com/ankane/mailkick/blob/master/README.md Include the `gibbon` gem if you are using Mailchimp for fetching opt-outs. ```ruby gem "gibbon", ">= 2" ``` -------------------------------- ### Access Mailkick Subscription Model Directly Source: https://context7.com/ankane/mailkick/llms.txt Interact with the underlying ActiveRecord model for subscription records. Supports polymorphic associations and direct creation/deletion. ```ruby # Query all active subscriptions Mailkick::Subscription.all # => ActiveRecord::Relation # Find subscriptions for a specific user user = User.find(42) user.mailkick_subscriptions # => [#] # Find all subscribers to a list across all types Mailkick::Subscription.where(list: "newsletter") # Directly create / destroy (prefer model methods for business logic) Mailkick::Subscription.create!( subscriber: user, list: "newsletter" ) Mailkick::Subscription.where(subscriber: user, list: "newsletter").delete_all # Validations enforced by the model: Mailkick::Subscription.new(subscriber: user, list: "").valid? # => false # errors.full_messages => ["List can't be blank"] ``` -------------------------------- ### Rotate Message Verifier Secret for Legacy Tokens Source: https://context7.com/ankane/mailkick/llms.txt Use this to restore support for unsubscribe links generated before Mailkick 1.1.1, which used Marshal serialization and a legacy secret. ```ruby # config/initializers/mailkick.rb # Restore support for unsubscribe links generated before Mailkick 1.1.1 # (links signed with Marshal instead of JSON, using a legacy secret) previous_secret = "your-old-secret-token-here" Mailkick.message_verifier.rotate(previous_secret, serializer: Marshal) ``` -------------------------------- ### Unsubscribe User from a List Source: https://github.com/ankane/mailkick/blob/master/README.md Use the `unsubscribe` method on a user instance to remove them from a specific mailing list. ```ruby user.unsubscribe("sales") ``` -------------------------------- ### Injecting Unsubscribe Headers with Mailkick Source: https://context7.com/ankane/mailkick/llms.txt Use `mailkick_unsubscribe_url` within your mailer to automatically inject List-Unsubscribe headers. This ensures compliance and provides a one-click unsubscribe option for users. ```ruby class TransactionalMailer < ApplicationMailer def receipt(user, order) @user = user @order = order mailkick_unsubscribe_url(@user, "transactional") # triggers header injection mail(to: @user.email, subject: "Your receipt ##{order.id}") end end ``` -------------------------------- ### Add Unsubscribe Link to Text Emails Source: https://github.com/ankane/mailkick/blob/master/README.md Include an unsubscribe link in your plain text emails using the `mailkick_unsubscribe_url` helper. ```erb Unsubscribe: <%= mailkick_unsubscribe_url(@user, "sales") %> ``` -------------------------------- ### Check if User is Subscribed Source: https://github.com/ankane/mailkick/blob/master/README.md Use the `subscribed?` method to check if a user is currently subscribed to a given list. ```ruby user.subscribed?("sales") ``` -------------------------------- ### Generating Unsubscribe URL in ActionMailer Source: https://context7.com/ankane/mailkick/llms.txt Use the `mailkick_unsubscribe_url` helper within your ActionMailer mailers to generate a secure unsubscribe link for users. This helper can also automatically set RFC 8058 headers if `Mailkick.headers` is enabled. ```ruby # app/mailers/newsletter_mailer.rb class NewsletterMailer < ApplicationMailer def weekly(user) @user = user @unsubscribe_url = mailkick_unsubscribe_url(@user, "newsletter") mail(to: @user.email, subject: "This week in Rails") end end ``` -------------------------------- ### Mailkick.generate_token Source: https://context7.com/ankane/mailkick/llms.txt Generates the signed token embedded in unsubscribe URLs. Used internally by `mailkick_unsubscribe_url` but available for custom URL construction. ```APIDOC ## `Mailkick.generate_token` — Signed Subscription Token Generates the signed token embedded in unsubscribe URLs. Used internally by `mailkick_unsubscribe_url` but available for custom URL construction. ```ruby user = User.find(99) token = Mailkick.generate_token(user, "newsletter") # => "eyJfcmFpbHMiOnsibWVzc..." (a JSON MessageVerifier-signed string) # Build a raw URL without ActionMailer context: url = Rails.application.routes.url_helpers.url_for( controller: "mailkick/subscriptions", action: "unsubscribe", id: token, host: "example.com" ) # => "https://example.com/mailkick/subscriptions/TOKEN/unsubscribe" # Error handling: Mailkick.generate_token(nil, "newsletter") # raises ArgumentError: Missing subscriber Mailkick.generate_token(user, "") # raises ArgumentError: Missing list ``` ``` -------------------------------- ### Disable Mailkick Automatic Mounting Source: https://context7.com/ankane/mailkick/llms.txt Configure Mailkick to disable automatic mounting of its engine at `/mailkick`. This allows for manual mounting or complete disabling. ```ruby # Disable automatic mounting (if you want to mount manually or not at all): # config/initializers/mailkick.rb Mailkick.mount = false # Manual mount in config/routes.rb: Rails.application.routes.draw do mount Mailkick::Engine => "/email-preferences" end ``` -------------------------------- ### Unsubscribe Link in Plain-Text Email View Source: https://context7.com/ankane/mailkick/llms.txt Include the unsubscribe URL in the plain-text version of your emails for users who prefer or only receive plain text. This ensures the unsubscribe option is available across all email formats. ```erb <%# Plain-text variant — app/views/newsletter_mailer/weekly.text.erb %> Hello <%= @user.first_name %>, Here is your weekly digest… Unsubscribe: <%= mailkick_unsubscribe_url(@user, "newsletter") %> ``` -------------------------------- ### Add Unsubscribe Link to HTML Emails Source: https://github.com/ankane/mailkick/blob/master/README.md Embed an unsubscribe link in your HTML emails using the `mailkick_unsubscribe_url` helper. ```erb <%= link_to "Unsubscribe", mailkick_unsubscribe_url(@user, "sales") %> ``` -------------------------------- ### Class Scope for Subscribed Users Source: https://context7.com/ankane/mailkick/llms.txt Query for subscribed users using the `subscribed` class scope. This scope returns an ActiveRecord::Relation, allowing further querying or iteration. ```ruby # ---- Class scope ---- User.subscribed("newsletter") # => ActiveRecord::Relation of subscribed users User.subscribed("newsletter").count # => integer User.subscribed("newsletter").each do |u| NewsletterMailer.weekly(u).deliver_later end ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.