Coder Social home page Coder Social logo

maily_herald's Introduction

Build Status

MailyHerald

MailyHerald with its Web UI

MailyHerald is a Ruby on Rails gem that helps you send and manage your application mailings. Think of Maily as a self-hosted Mailchimp alternative you can easily integrate into your site. MailyHerald is great both for email marketing and conducting the daily stream of notifications you send to your users.

With MailyHerald you can send:

  • ad-hoc mailings - arbitrary emails sent to one or more users at a given point in time (i.e. password reset instructions, special offers, announcements),
  • one-time mailings (i.e. account activation, welcome emails),
  • periodical mailings (i.e. weekly notifications, reminders),
  • mailing sequences - multiple ordered emails delivered with certain delays from a specific point in time (i.e. onboarding emails, site feature overview, reminders).

Maily keeps track of user subscriptions and allows them to easily opt out. You can define who receives which emails and specify conditions that control delivery. All mailing deliveries are scheduled individually for each recipient, tracked and logged.

Maily seamlessly integrates with your app. It can use your regular Action Mailers or you can build email contents with Liquid markup templates.

Core Maily features are accessible for Rails programmers via the API. Apart from that, Maily has a nice Web UI provided by a separate maily_herald-webui gem.

Requirements

Both Ruby on Rails 3.2 and 4 are supported.

Installation

Simply just run

gem install maily_herald

or put in your Gemfile

gem "maily_herald"

Features

  • Designed for Ruby on Rails
  • Self-hosted
  • Seamless and flexible integration
  • Asynchronous email processing
  • Per-recipient delivery scheduling
  • Great both for developers (API) and end users (Web UI)
  • On-the-fly email templating using Liquid syntax
  • Four different mailing types
  • User-friendly subscription management i.e. via automatic & personal opt-out links
  • Correspondence logging
  • Delivery conditions

Development state

MailyHerald is a relatively young piece of software and it has been deployed in a few different production environments.

If you decide to use it, please tell us what you think about it. You can post some issues on GitHub or email us directly. We're waiting for your feedback.

Here are some things we would like to implement in the future:

  • message analytics,
  • link tracking,
  • fetching bounces from email service (Amazon SES, Mandrill, Sendgrid etc.),
  • better templating,
  • put your beloved feature here.

How it works

There are a few key concepts that need to be explained in order to understand how Maily works. Some of them are similar to what you might know from other conventional email marketing software. Others come strictly from the Ruby on Rails world.

Entities

Entities are your mailing recipients. They will probably be represented in your application by User model.

Mailings

You usually send single emails to your users, one at a time. Mailing is a bunch of emails sent out to many users. MailyHerald allows you to send four types of Mailings: ad-hoc, one-times, periodicals and sequences.

Contexts

Maily Contexts provide a layer of abstraction for accessing collections of entities and their attributes.

There are three main things that Contexts do:

  • They define sets of entities via standard Rails scopes (i.e. User.activated meaning all application users that activated their accounts).
  • They specify destination email addresses for entities (i.e. you can define that User#email method returns email address or specify a custom proc that does that).
  • They specify additional entity attributes that can be used inside Mailing templates, conditions etc. (essentially, any attribute accessible via Liquid).

Lists and Subscriptions

Lists are sets of entities that receive certain mailings. Entities are added to Lists by creating Subscriptions. It is entirely up to you how you manage subscriptions in the application. Typically, you would put a checkbox in the user's profile page which subscribes and unsubscribes them from mailing lists.

Each Subscription has a unique token allowing users to be provided with one-click opt-out links.

Mailers

Mailers are the standard way of sending emails in Rails applications. MailyHerald hooks into ActionMailer internals and allows you to send Mailings just like you send your regular emails. All you need to do is inherit MailyHerald::Mailer in your Mailer.

There's also a possibility to send Mailings without using any of your custom Mailers. MailyHerald::Mailer is in this case used implicitly; email body and subject is stored directly in your Mailing definition as a Liquid template. Liquid gives you access to entity attributes defined in the Context. This way of creating Mailings is especially useful within the Web UI where you can build new Mailing by simply typing in its template.

Delivery

MailyHerald uses the great gem Sidekiq to process deliveries in the background. This applies to all kinds of Mailings - their deliveries are scheduled individually for each entity on the subscription list.

Maily checks periodically for scheduled mailings, and then the time comes, queues them for delivery. This is the job of MailyHerald Paperboy - a tiny daemon that runs in the background and checks the schedules. It is essential to make your mailings work.

Usage

Let's assume your entities are your User model objects. Read on in order to find out how to get started with Maily.

Migrations

Install engine migrations and run them.

rake maily_herald:install:migrations
rake db:migrate

Defaults (optional)

In some cases, you need to specify default from and host mailer options in your application in order to ensure proper email rendering:

# config/application.rb
config.action_mailer.default_options = { from: "[email protected]" }
config.action_mailer.default_url_options = { host: "mailyherald.org" }

Initializer

Generate an initializer:

rails g maily_herald:install

This will create the following file:

# config/initializers/maily_herald.rb
MailyHerald.setup do |config|
  # Put your contexts, mailing definitions etc. here.
end

There are few things you need to put there.

Set up your context

Say, for example, you want to deliver your mailings to all your active users:

config.context :active_users do |context|
  context.scope {User.active}
  context.destination {|user| user.email}
  
  # Alternatively, you can specify destination as attribute name:
  # context.destination = :email
end

Set up your lists

The following means that all users in the :active_users context scope can be subscribed to the :newsletters list.

config.list :newsletters do |list|
  list.context_name = :active_users
end

MailyHerald lists are opt-in lists. They are empty by default, so make sure to add entities to them, i.e. by using MailyHerald.subscribe method.

Set up your mailings

config.one_time_mailing :hello do |mailing|
  mailing.title = "Hello mailing"
  mailing.list = :notifications
  mailing.mailer_name = "UserMailer"
  mailing.start_at = Proc.new{|user| user.created_at + 1.hour}
  mailing.enable # mailings are disabled by default
end

config.periodical_mailing :weekly_newsletter do |mailing|
  mailing.title = "Weekly newsletter"
  mailing.list = :newsletters
  mailing.mailer_name = "UserMailer"
  mailing.start_at = Proc.new{|user| user.created_at + 1.week}
  mailing.period = 1.week
  mailing.enable
end

Configuration locking

By default, all contexts, lists and mailings initialized inside MailyHerald.setup block are locked and cannot be edited at runtime. This constraint is enforced to maintain the nature of RoR application initializer files. Things set up in the initializer should always be read-only because the initializer is executed every time the application spawns.

If you need to set up mailings programmatically and make them unlocked, don't simply use MailyHerald.setup. Instead, use methods from the MailyHerald class directly. You can then enter your code, i.e. in a DB seed file or a rake task.

You would typically put your MailyHerald.setup block in the Maily initializer file. Keep in mind that this file is evaluated every time Rails boots up, so changes made there (i.e. new mailings added) will be reflected at next application launch.

Different mailing types

AdHocMailing is the most similar to regular Ruby on Rails emails sent using ActionMailer. The only difference is that their delivery is handled by Maily and thus logged and optionally backgrounded.

OneTimeMailing deliveries are performed only once to a single recipient at a scheduled delivery time. It is fully automatic and its delivery can't be manually triggered. OneTimeMailing schedules are created based on the start_at attribute individually for each recipient.

PeriodicalMailing handles multiple, periodical email deliveries to individual recipients. It is also automatic. Apart from the start_at attribute, it also uses a period which defines the time distance between consecutive deliveries.

Sequence allows you to send multiple different mailings to a given entity with various time delays. It is achieved by defining SequenceMailings associated to a Sequence with delivery delays stored in their absolute_delay attributes. A mailing delivery delay is calculated from a point in time defined in Sequence's start_at attribute (similar to PeriodicalMailing).

Procs and Liquid syntax

Mailing attributes such as start_at and conditions can be defined programmatically as procs or as a string using Liquid syntax. Here's an example of those two cases:

# Using Proc:
mailing.start_at = Proc.new{|user| user.created_at + 5.minutes}

# Using Liquid:
mailing.start_at = "user.created_at | plus: 5, 'minutes'"

Liquid syntax is obviously more convenient for non-programmers (and can be safely used i.e. in WebUI) but requires some additional setup inside Maily Context. Context attributes available within Liquid templates have to be defined:

config.context :all_users do |context|
  context.scope {User.all}
  context.destination = :email
  context.attributes do |user| 
    attribute_group(:user) do
      attribute(:name) {user.name}
      attribute(:email) {user.email}
      attribute(:created_at) {user.created_at}
    end
  end
end

Maily provides some Liquid filters that are particularly useful for time manipulation:

  • plus: <number>, '<period>'
  • minus: <number>, '<period>'

They can be used for incrementing and decrementing the time value. <number> is simply an integer; <period> is one of 'minutes', 'hours', 'days' etc.

The Mailing body can also be defined programmatically using custom Mailer. The other way is to not define explicit Mailer but rather set the subject and template as Liquid templates.

# Using custom ActionMailer:
config.ad_hoc_mailing :hello do |mailing|
  mailing.list = :all_users
  mailing.mailer_name = "UserMailer" # In this case, you should have a mailer called 'UserMailer' that defines method 'hello'.
  mailing.enable
end

# Using Liquid templates:
config.ad_hoc_mailing :hello do |mailing|
  mailing.list = :all_users
  mailing.subject = "Hello {{user.name}}!"
  mailing.template = "What's up?"
  mailing.enable
end

Mailers

If you want to use your custom ActionMailers with Maily, you need to modify them a bit.

First, each Mailer you want to use with MailyHerald needs to extend the MailyHerald::Mailer class.

Then each Mailer method must be named after the mailing identification name and accept only one parameter, which will be your entity (i.e. User class object).

This setup gives you additional instance variables available to you in your views:

  • @maily_entity - entity you are sending this email to,
  • @maily_mailing - Mailing you are sending,
  • @maily_subscription - MailyHerald::Subscription object related to this entity and Mailing,

Here's the complete example:

class UserMailer < MailyHerald::Mailer
  def hello user
    mail :subject => "Hi there #{user.name}!"
  end
end

Opt-outs

MailyHerald allows entities to easily opt-out using direct unsubscribe urls. Each entity subscription has its own token and based on this token, the opt-out URL is generated.

To process user opt-out requests, you need to mount Maily into your app:

# config/routes.rb

mount MailyHerald::Engine => "/unsubscribe", :as => "maily_herald_engine"

Maily provides you with a URL helper that generates opt-out URLs (i.e. in your ActionMailer views):

maily_herald_engine.maily_unsubscribe_url(@maily_subscription)

When you use Liquid for email templating, your context will always include the special attribute subscription that allows you to easily output unique opt-out URLs. Use the following syntax:

{{subscription.token_url}}

Visiting an opt-out URL disables the subscription and by default redirects to "/".

Delivery and background processing

Scheduled MailyHerald mailings are always sent in the background.

In order to make your deliveries work, you need to run MailyHerald Paperboy, which will take care of it:

$ bundle exec maily_herald paperboy --start

Paperboy will monitor your mailing schedules and queue their delivery. The actual sending of emails is handled in the background as a Sidekiq job, so make sure you run Sidekiq alongside Paperboy.

You can't manually trigger delivery of one-time, periodical and sequence mailings. Their schedules and deliveries are maintained automatically.

Ad-hoc mailing, on the other hand, can (and should!) be manually scheduled for delivery:

MailyHerald.ad_hoc_mailing(:password_reset).schedule_delivery_to User.first, Time.now

Alernatively, for Action Mailer compatibility, you can use the standard syntax for sending emails:

UserMailer.password_reset(User.first).deliver

This code will process email delivery immediately, in the current thread, just like a regular Action Mailer.

That's it!

Your Maily setup is now complete.

See API Docs for more details about usage and configuration.

Configuring

You can configure your Maily using the config file config/maily_herald.yml. Supported options:

  • verbose: true,false
  • logfile: where all the stuff is logged, usually 'log/maily_herald.log`
  • pidfile: file name
  • redis_url: string
  • redis_namespace: string
  • redis_driver: string

Other stuff

Periodical mailing scheduling

Periodical mailing is kind of a special one and has two modes of scheduling: general and individual. If you specify start_at as an absolute time, i.e. "2111-01-01 11:11", it goes into general scheduling mode and consecutive mailings will be delivered to all subscribed entities at the same time at every period. This way you can send, for example, weekly newsletters every Monday to all subscribers.

When you specify start_at as an individual time, i.e. "user.start_at", individual scheduling mode will be enabled. In this case, delivery periods will count individually for each user and deliveries will be made accordingly.

Individual scheduling mode is the only mode available for all other mailing types.

Deployments

Maily has a built-in simple support for Capistrano. It supports both v2 and v3 and automates the task of starting, stopping and restarting the Paperboy daemon during deployments.

To enable, just put the following line into your Capfile:

require 'maily_herald/capistrano'

Opt-out URLs

By default, visiting an opt-out URL silently disables the subscription and redirects to "/". You can easily customize the redirect path by specifying token_redirect proc:

# Evaluated within config:
config.token_redirect do |controller, subscription|
  # This is just an example, put here whatever you want.
  controller.view_context.unsubscribed_path
end

In case you need more customization, you can always overwrite MailyHerald::TokensController and its get method:

# app/controllers/maily_herald/tokens_controller.rb
module MailyHerald
  class TokensController < ::ApplicationController
    before_action :find_subscription

    def get
      if @subscription && @subscription.active?
        @subscription.deactivate!
        # now render some custom view
      else
        redirect_to(main_app.root_url)
      end
    end

    private

    def find_subscription
      @subscription ||= MailyHerald::Subscription.find_by_token(params[:token])
    end
  end
end

Redis namespaces

If you want to use MailyHerald with non-standard Redis namespace, make sure your Sidekiq is also configured properly. This usually involves creating an initializer file:

# config/initializers/sidekiq.rb
Sidekiq.configure_server do |config|
  config.redis = { namespace: 'maily' }
end
Sidekiq.configure_client do |config|
  config.redis = { namespace: 'maily' }
end

Then make sure you tell Maily about the change:

# config/maily_herald.yml
---
:redis_namespace: maily

Contributing

Please aim your pull requests to 'development' branch.

Your changes should be well tested. To set up test environment just run:

RAILS_ENV=test rake db:setup
rspec
guard # execute specs interactively

More Information

Although we work hard on MailyHerald development, we can't guarantee it is free of bugs. If you find one, please make sure to report it using issues tracker on Github. You can also post your feature requests there too.

License

LGPLv3 License. Copyright 2013-2015 Sology. http://www.sology.eu

Initial development sponsored by Smart Language Apps Limited http://smartlanguageapps.com/

maily_herald's People

Contributors

ardahaal avatar ljachymczyk avatar marcintichoniuk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

maily_herald's Issues

Rails assets:precompile tries to connect to DB

I'm trying to deploy my application with maily_herald gem to Heroku, and it fails with this reason:

could not connect to server: Connection refused
Is the server running on host "127.0.0.1" and accepting
TCP/IP connections on port xxxx?

I reproduced this on local machine

RAILS_ENV=production rake assets:precompile
and got this error:

RAILS_ENV=production rake assets:precompile --trace
** Invoke assets:precompile (first_time)
** Invoke assets:environment (first_time)
** Execute assets:environment
** Invoke environment (first_time)
** Execute environment
rake aborted!
ActiveRecord::NoDatabaseError: FATAL:  database "my_prod_db_name" does not exist
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/postgresql_adapter.rb:665:in `rescue in connect'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/postgresql_adapter.rb:655:in `connect'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/postgresql_adapter.rb:242:in `initialize'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/postgresql_adapter.rb:44:in `new'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/postgresql_adapter.rb:44:in `postgresql_connection'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract/connection_pool.rb:438:in `new_connection'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract/connection_pool.rb:448:in `checkout_new_connection'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract/connection_pool.rb:422:in `acquire_connection'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract/connection_pool.rb:349:in `block in checkout'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/monitor.rb:211:in `mon_synchronize'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract/connection_pool.rb:348:in `checkout'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract/connection_pool.rb:263:in `block in connection'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/monitor.rb:211:in `mon_synchronize'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract/connection_pool.rb:262:in `connection'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract/connection_pool.rb:571:in `retrieve_connection'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_handling.rb:113:in `retrieve_connection'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_handling.rb:87:in `connection'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/model_schema.rb:230:in `table_exists?'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/maily_herald-0.9.2/lib/maily_herald.rb:166:in `collect'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/maily_herald-0.9.2/lib/maily_herald.rb:166:in `schema_loaded?'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/maily_herald-0.9.2/lib/maily_herald.rb:159:in `setup'
/Users/stanislav/Projects/championmailer/config/initializers/maily_herald.rb:1:in `<top (required)>'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:268:in `load'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:268:in `block in load'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:240:in `load_dependency'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:268:in `load'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/engine.rb:652:in `block in load_config_initializer'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/notifications.rb:166:in `instrument'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/engine.rb:651:in `load_config_initializer'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/engine.rb:616:in `block (2 levels) in <class:Engine>'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/engine.rb:615:in `each'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/engine.rb:615:in `block in <class:Engine>'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/initializable.rb:30:in `instance_exec'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/initializable.rb:30:in `run'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/initializable.rb:55:in `block in run_initializers'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:226:in `block in tsort_each'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:348:in `block (2 levels) in each_strongly_connected_component'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:420:in `block (2 levels) in each_strongly_connected_component_from'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:429:in `each_strongly_connected_component_from'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:419:in `block in each_strongly_connected_component_from'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/initializable.rb:44:in `each'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/initializable.rb:44:in `tsort_each_child'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:413:in `call'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:413:in `each_strongly_connected_component_from'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:347:in `block in each_strongly_connected_component'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:345:in `each'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:345:in `call'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:345:in `each_strongly_connected_component'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:224:in `tsort_each'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:203:in `tsort_each'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/initializable.rb:54:in `run_initializers'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/application.rb:352:in `initialize!'
/Users/stanislav/Projects/championmailer/config/environment.rb:5:in `<top (required)>'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:274:in `require'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:274:in `block in require'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:240:in `load_dependency'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:274:in `require'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/application.rb:328:in `require_environment!'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/application.rb:457:in `block in run_tasks_blocks'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:240:in `call'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:240:in `block in execute'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:235:in `each'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:235:in `execute'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:179:in `block in invoke_with_call_chain'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/monitor.rb:211:in `mon_synchronize'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:172:in `invoke_with_call_chain'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:165:in `invoke'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/sprockets-rails-2.3.3/lib/sprockets/rails/task.rb:64:in `block (2 levels) in define'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:240:in `call'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:240:in `block in execute'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:235:in `each'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:235:in `execute'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:179:in `block in invoke_with_call_chain'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/monitor.rb:211:in `mon_synchronize'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:172:in `invoke_with_call_chain'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:201:in `block in invoke_prerequisites'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:199:in `each'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:199:in `invoke_prerequisites'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:178:in `block in invoke_with_call_chain'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/monitor.rb:211:in `mon_synchronize'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:172:in `invoke_with_call_chain'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:165:in `invoke'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/application.rb:150:in `invoke_task'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/application.rb:106:in `block (2 levels) in top_level'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/application.rb:106:in `each'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/application.rb:106:in `block in top_level'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/application.rb:115:in `run_with_threads'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/application.rb:100:in `top_level'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/application.rb:78:in `block in run'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/application.rb:176:in `standard_exception_handling'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/application.rb:75:in `run'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rake-10.4.2/bin/rake:33:in `<top (required)>'
/usr/local/var/rbenv/versions/2.2.2/bin/rake:23:in `load'
/usr/local/var/rbenv/versions/2.2.2/bin/rake:23:in `<main>'
PG::ConnectionBad: FATAL:  database "championmailer" does not exist
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/postgresql_adapter.rb:655:in `initialize'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/postgresql_adapter.rb:655:in `new'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/postgresql_adapter.rb:655:in `connect'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/postgresql_adapter.rb:242:in `initialize'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/postgresql_adapter.rb:44:in `new'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/postgresql_adapter.rb:44:in `postgresql_connection'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract/connection_pool.rb:438:in `new_connection'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract/connection_pool.rb:448:in `checkout_new_connection'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract/connection_pool.rb:422:in `acquire_connection'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract/connection_pool.rb:349:in `block in checkout'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/monitor.rb:211:in `mon_synchronize'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract/connection_pool.rb:348:in `checkout'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract/connection_pool.rb:263:in `block in connection'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/monitor.rb:211:in `mon_synchronize'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract/connection_pool.rb:262:in `connection'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract/connection_pool.rb:571:in `retrieve_connection'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_handling.rb:113:in `retrieve_connection'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_handling.rb:87:in `connection'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.4/lib/active_record/model_schema.rb:230:in `table_exists?'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/maily_herald-0.9.2/lib/maily_herald.rb:166:in `collect'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/maily_herald-0.9.2/lib/maily_herald.rb:166:in `schema_loaded?'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/maily_herald-0.9.2/lib/maily_herald.rb:159:in `setup'
/Users/stanislav/Projects/championmailer/config/initializers/maily_herald.rb:1:in `<top (required)>'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:268:in `load'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:268:in `block in load'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:240:in `load_dependency'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:268:in `load'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/engine.rb:652:in `block in load_config_initializer'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/notifications.rb:166:in `instrument'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/engine.rb:651:in `load_config_initializer'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/engine.rb:616:in `block (2 levels) in <class:Engine>'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/engine.rb:615:in `each'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/engine.rb:615:in `block in <class:Engine>'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/initializable.rb:30:in `instance_exec'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/initializable.rb:30:in `run'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/initializable.rb:55:in `block in run_initializers'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:226:in `block in tsort_each'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:348:in `block (2 levels) in each_strongly_connected_component'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:420:in `block (2 levels) in each_strongly_connected_component_from'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:429:in `each_strongly_connected_component_from'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:419:in `block in each_strongly_connected_component_from'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/initializable.rb:44:in `each'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/initializable.rb:44:in `tsort_each_child'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:413:in `call'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:413:in `each_strongly_connected_component_from'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:347:in `block in each_strongly_connected_component'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:345:in `each'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:345:in `call'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:345:in `each_strongly_connected_component'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:224:in `tsort_each'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/tsort.rb:203:in `tsort_each'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/initializable.rb:54:in `run_initializers'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/application.rb:352:in `initialize!'
/Users/stanislav/Projects/championmailer/config/environment.rb:5:in `<top (required)>'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:274:in `require'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:274:in `block in require'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:240:in `load_dependency'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:274:in `require'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/application.rb:328:in `require_environment!'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/railties-4.2.4/lib/rails/application.rb:457:in `block in run_tasks_blocks'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:240:in `call'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:240:in `block in execute'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:235:in `each'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:235:in `execute'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:179:in `block in invoke_with_call_chain'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/monitor.rb:211:in `mon_synchronize'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:172:in `invoke_with_call_chain'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:165:in `invoke'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/sprockets-rails-2.3.3/lib/sprockets/rails/task.rb:64:in `block (2 levels) in define'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:240:in `call'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:240:in `block in execute'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:235:in `each'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:235:in `execute'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:179:in `block in invoke_with_call_chain'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/monitor.rb:211:in `mon_synchronize'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:172:in `invoke_with_call_chain'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:201:in `block in invoke_prerequisites'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:199:in `each'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:199:in `invoke_prerequisites'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:178:in `block in invoke_with_call_chain'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/monitor.rb:211:in `mon_synchronize'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:172:in `invoke_with_call_chain'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/task.rb:165:in `invoke'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/application.rb:150:in `invoke_task'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/application.rb:106:in `block (2 levels) in top_level'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/application.rb:106:in `each'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/application.rb:106:in `block in top_level'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/application.rb:115:in `run_with_threads'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/application.rb:100:in `top_level'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/application.rb:78:in `block in run'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/application.rb:176:in `standard_exception_handling'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/2.2.0/rake/application.rb:75:in `run'
/usr/local/var/rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rake-10.4.2/bin/rake:33:in `<top (required)>'
/usr/local/var/rbenv/versions/2.2.2/bin/rake:23:in `load'
/usr/local/var/rbenv/versions/2.2.2/bin/rake:23:in `<main>'
Tasks: TOP => environment

Add track opens and clicks

Hello, I think this is very important for an email marketing campaign.

Know how many people you sent the email opened, and also track clicks

Thank you ! I want to know if you are planning to add those features, that would make maily_herald more close to mailchimp.

Regards

Accessing devise/cancancan helpers in initializer doesn't work

In the config/initializer/maily_herald.rb file I'd like to limit scope of available users based on who is signed in. This is a multi-tenant application that has different sets of users based on account.

In the example documentation, the scope context given is always User.all. I'm trying replace this logic using Devise or CanCanCan's current_user or current_ability helpers; eg.:

  config.context :all_users do |context|
    context.scope { User.where(:account => current_user.account) }
    context.destination {|user| user.email}
    context.attributes do |user|
      attribute_group(:user) do
        attribute(:email) {user.email}
        attribute(:created_at) {user.created_at}
      end
    end
  end

but cannot access Devise (and Devise helpers like current_user) in MailyHerald's initializer file. Any guidance is appreciated.

Paperboy stops

Hi, I'm using maily_herald in production, and from time to time every day paperboy stops running.
I need to be constantly checking on the email delivery and restarting the process if needed, has this happened to you?

Thanks!

Rails 5 support?

Has anyone made the gem work with Rails 5?

I did some preliminary testing on Rails 5, and there are some issues.

I made maily_herald-webui work with a few tweaks on a fork that I created:
https://github.com/aldefouw/maily_herald-webui/commits/master

My changes were mainly to some out of date dependencies. I also had to tweak the version code a bit to send the appropriate number of objects to the methods for Rails 5.

The web interface seems to be working pretty well, but I can't quite seem to get any mail to deliver. It seems like it gets tripped up when it tries to process the Mailers (I can post the error I am receiving if that helps) .. so I am wondering if Rails 5 changed something about ActionMailer that is incompatible.

I will do more research and try to fix it myself, but I just didn't want to be duplicating efforts if someone else is already working on Rails 5 compatibility.

If I can't make it work for Rails 5, I'll probably be forced to use some other solution. Looks really cool what's made so far!

Thanks!

ng: Subscriptions never work

Whenever MailyHerald::List::create_subscription_for is called, s.active_changed? on MailyHerald::Subscription:26 is always false (because it was just created), so it never generates a schedule. Which means it never sends any emails.

I think what is missing is the following line in MailyHerald::Subscription:

    after_create :update_schedules, if: Proc.new{|s| s.active}

debugger gem doesn't work with Ruby 2.1+

I was doing some development on this gem, I updated my Ruby version to 2.1.4 and after update gems I see that Debugger gem is no longer compatible with newer ruby versions, I suggest use byebug instead.

NoMethodError at /user undefined method `[]' for false:FalseClass

Following this guide step by step, after start the server and try to register a new user a confirmation email should be sent through Maily Herald

but I get this instead

NoMethodError at /user
undefined method `[]' for false:FalseClass

maily_herald (0.9.3) lib/maily_herald.rb

# Gets the Maily logger.
def logger
  unless MailyHerald::Logging.initialized?
    opts = {
      level: options[:verbose] ? Logger::DEBUG : Logger::INFO,
    }
    opts[:target] = options[:logfile] if options[:logfile]
    MailyHerald::Logging.initialize(opts)
  end

Say Thank you!

I just wanted to say Thank you for this great job, you Rock! I will add my contributions soon!!

[Capistrano] Cannot start paperboy by defaults

Integrating MailyHerald into Capistrano results in:

03:04 maily_herald:restart
      01 /usr/share/rvm/bin/rvm 2.3.3 do bundle exec maily_herald paperboy --restart
      01 2018-11-28T04:02:58Z 8444 [Maily#cli] INFO: Started with options: {:mode=>:paperboy, :action=>:restart, :daemon=>true}
      01 You really should set a logfile if you're going to daemonize
      01
      01 /home/cems/cems/shared/bundle/ruby/2.3.0/gems/maily_herald-0.9.4/lib/maily_herald/cli.rb:200:in `daemonize'
      01 /home/cems/cems/shared/bundle/ruby/2.3.0/gems/maily_herald-0.9.4/lib/maily_herald/cli.rb:45:in `paperboy'
      01 /home/cems/cems/shared/bundle/ruby/2.3.0/gems/maily_herald-0.9.4/bin/maily_herald:10:in `<top (required)>'
      01 /home/cems/cems/shared/bundle/ruby/2.3.0/bin/maily_herald:22:in `load'
      01 /home/cems/cems/shared/bundle/ruby/2.3.0/bin/maily_herald:22:in `<top (required)>'
      01 /home/cems/.rvm/gems/ruby-2.3.3/gems/bundler-1.16.4/lib/bundler/cli/exec.rb:74:in `load'
      01 /home/cems/.rvm/gems/ruby-2.3.3/gems/bundler-1.16.4/lib/bundler/cli/exec.rb:74:in `kernel_load'
      01 /home/cems/.rvm/gems/ruby-2.3.3/gems/bundler-1.16.4/lib/bundler/cli/exec.rb:28:in `run'
      01 /home/cems/.rvm/gems/ruby-2.3.3/gems/bundler-1.16.4/lib/bundler/cli.rb:424:in `exec'
      01 /home/cems/.rvm/gems/ruby-2.3.3/gems/bundler-1.16.4/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
      01 /home/cems/.rvm/gems/ruby-2.3.3/gems/bundler-1.16.4/lib/bundler/vendor/thor/lib/thor/invocation.rb:126:in `invoke_command'
      01 /home/cems/.rvm/gems/ruby-2.3.3/gems/bundler-1.16.4/lib/bundler/vendor/thor/lib/thor.rb:387:in `dispatch'
      01 /home/cems/.rvm/gems/ruby-2.3.3/gems/bundler-1.16.4/lib/bundler/cli.rb:27:in `dispatch'
      01 /home/cems/.rvm/gems/ruby-2.3.3/gems/bundler-1.16.4/lib/bundler/vendor/thor/lib/thor/base.rb:466:in `start'
      01 /home/cems/.rvm/gems/ruby-2.3.3/gems/bundler-1.16.4/lib/bundler/cli.rb:18:in `start'
      01 /home/cems/.rvm/gems/ruby-2.3.3/gems/bundler-1.16.4/exe/bundle:30:in `block in <top (required)>'
      01 /home/cems/.rvm/gems/ruby-2.3.3/gems/bundler-1.16.4/lib/bundler/friendly_errors.rb:124:in `with_friendly_errors'
      01 /home/cems/.rvm/gems/ruby-2.3.3/gems/bundler-1.16.4/exe/bundle:22:in `<top (required)>'
      01 /home/cems/.rvm/gems/ruby-2.3.3/bin/bundle:22:in `load'
      01 /home/cems/.rvm/gems/ruby-2.3.3/bin/bundle:22:in `<main>'
      01 /home/cems/.rvm/gems/ruby-2.3.3/bin/ruby_executable_hooks:24:in `eval'
      01 /home/cems/.rvm/gems/ruby-2.3.3/bin/ruby_executable_hooks:24:in `<main>'

Apparently, the paperboy command in the README, which starts paperboy in daemon mode, doesn't work without specifying -L option. I don't know if I'm missing anything?

Anyway:

  • Capistrano task should be fixed.
  • The paperboy command in the document should be updated, either remove --start or add -L.

Can't send Devise's confirmation_email

Error:

NoMethodError: protected method `process' called for #UserMailer:0x0055f87edc6af0

Note that everything works fine without config.parent_mailer = 'MailyHerald::Mailer' in Devise's config.

Code

User model is skipping the normal devise confirmation email

class User < ApplicationRecord
  before_create :skip_confirmation_email
  after_create :send_confirmation_email

  def send_confirmation_email
    delay.send_confirmation_instructions # have also tried without `delay`
  end

  def skip_confirmation_email
    skip_confirmation_notification!
  end
end

Devise mailer config (from your wiki)

Devise.setup do |config|
  # Configure the class responsible to send e-mails.
  config.mailer = 'UserMailer'
  config.parent_mailer = 'MailyHerald::Mailer'
end

MailyHerald setup

MailyHerald.setup do |config|
  config.ad_hoc_mailing :confirmation_instructions do |mailing|
    mailing.title = 'Confirmation Instructions'
    mailing.list = :all_users
    mailing.mailer_name = 'UserMailer'
    mailing.enable
  end
end

And the UserMailer

class UserMailer < Devise::Mailer
  helper :application # gives access to all helpers defined within `application_helper`.
  include Devise::Controllers::UrlHelpers # Optional. eg. `confirmation_url`
  default from: '"example.net" <[email protected]>', template_path: 'devise/mailer' # to make sure that mailer uses the devise views

  def confirmation_instructions(record, opts = {})
    @token = record.confirmation_token
    devise_mail(record, :confirmation_instructions, opts)
  end
end

Full stacktrace:

NoMethodError: protected method `process' called for #<UserMailer:0x0055f87edc6af0>
Did you mean?  proc
  from action_mailer/message_delivery.rb:105:in `block in processed_mailer'
  from action_mailer/message_delivery.rb:104:in `tap'
  from action_mailer/message_delivery.rb:104:in `processed_mailer'
  from action_mailer/message_delivery.rb:95:in `deliver_now'
  from sidekiq/extensions/action_mailer.rb:33:in `deliver'
  from sidekiq/extensions/action_mailer.rb:22:in `perform'
  from sidekiq/processor.rb:152:in `execute_job'
  from sidekiq/processor.rb:134:in `block (2 levels) in process'
  from sidekiq/middleware/chain.rb:128:in `block in invoke'
  from sidekiq/middleware/server/active_record.rb:6:in `call'
  from sidekiq/middleware/chain.rb:130:in `block in invoke'
  from sidekiq/middleware/server/retry_jobs.rb:74:in `call'
  from sidekiq/middleware/chain.rb:130:in `block in invoke'
  from sidekiq/middleware/server/logging.rb:11:in `block in call'
  from sidekiq/logging.rb:32:in `with_context'
  from sidekiq/middleware/server/logging.rb:7:in `call'
  from sidekiq/middleware/chain.rb:130:in `block in invoke'
  from sidekiq/middleware/chain.rb:133:in `invoke'
  from sidekiq/processor.rb:129:in `block in process'
  from sidekiq/processor.rb:168:in `stats'
  from sidekiq/processor.rb:128:in `process'
  from sidekiq/processor.rb:80:in `process_one'
  from sidekiq/processor.rb:68:in `run'
  from sidekiq/util.rb:17:in `watchdog'
  from sidekiq/util.rb:25:in `block in safe_thread'

Configure redis_url per environment ?

How can I configure the redis_url per environment ? Is there any way to do that ?

If not, I think the way ActiveRecord handles this with ENV vars can work.

# Loads and returns the configuration of the database.
def database_configuration
  yaml = paths["config/database"].first
  if File.exist?(yaml)
    require "erb"
    YAML.load ERB.new(IO.read(yaml)).result
  elsif ENV['DATABASE_URL']
    nil
  else
    raise "Could not load database configuration. No such file - #{yaml}"
  end
rescue Psych::SyntaxError => e
  raise "YAML syntax error occurred while parsing #{paths["config/database"].first}. " \
        "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
        "Error: #{e.message}"
end

I can work on PR for this if you think is a good idea.

Thanks!

License missing from gemspec

Some companies will only use gems with a certain license.
The canonical and easy way to check is via the gemspec
via e.g.

spec.license = 'MIT'
# or
spec.licenses = ['MIT', 'GPL-2']

There is even a License Finder to help companies ensure all gems they use
meet their licensing needs. This tool depends on license information being available in the gemspec.
Including a license in your gemspec is a good practice, in any case.

How did I find you?

I'm using a script to collect stats on gems, originally looking for download data, but decided to collect licenses too,
and make issues for missing ones as a public service :)
https://gist.github.com/bf4/5952053#file-license_issue-rb-L13 So far it's going pretty well

I can't use custome action mailer

class OutboxMailer < MailyHerald::Mailer
def newsletter outbox
end
end

OutboxMailer.newsletter(outbox)
This is occur this error
(Object doesn't support #inspect)

Running tests

Im trying to run tests, however when I try to set up the database

rake db:setup

Rake is aborted and I get the following message:
ActiveRecord::RecordInvalid: Validation failed: List can't be blank, List can't be blank

If you provide some instructions for running tests that would be great.

Newbie in Ruby on Rails, please help me get maily herald running.

Dear maily_herard team,
first, a big thank you for publishing this interesting piece of software. There aren't much satisfying free alternatives in the world of email marketing. For example, PHPList's user experience is too crappy in my opinion.

I'm having a hard time running your software. I have the feeling that the documentation you have written is intended for experienced Ruby on Rails developers, and I am not (even if I have experience in administration otherwise). Could you please elaborate on the precise steps to do from a stock Debian distro for example? For example, apt-get install this and that... setup database with $ .. and $ ...

After hours of struggle, I could successfully run the sample_app, but the emails in the lists are locked (there are a few of them prefilled, people I don't know and I can't remove - I am afraid I could spam them). I am told to edit a file somewhere, but it's too much now and I want to give up.

Something else is not clear to me. I followed various tutorials and have the impression to have setup two database systems: postgresql AND redis. Are both dbs useful?

In a nutshell: please improve documentation for RoR newbies.

Analytics - Look into Ahoy_email

The README mentions that a number of analytics features still need to be added. What about recommending that users use ahoy_email if they'd like analytics? @ankane is an amazing developer and I highly recommend a number of his gems including Mailkick, Ahoy, Ahoy_Email, and blazer.

If users would like to see the stats within maily_herald's dashboard, the steps would be:

  1. Add a line to the README that users need to integrate ahoy_email for analytics.
  2. I can make a PR so maily_herald checks to see if the user is using ahoy_email. If the user is, then maily_herald's dashboard could pull the email analytics from the site' database. These analytics would be saved by ahoy_email.

How to skip a mailing?

I'm trying to skip a mailing when a condition I provide is false.
Please see the following code snippet:

  config.sequence :paid_onboarding do |seq|
    seq.title = "Paid Onboarding"
    seq.list = :paid_users
    seq.start_at = Proc.new { |user| user.account.subscription_end - 30.days } # days that have passed since subscription will be used in absolute_delay mailings below
    seq.enable

    # I WANT TO SKIP THIS MAILING FROM BEING SENT WHEN A CONDITION I PASS RETURNS FALSE
    # For example: Time.now < (user.account.subscription_end + 45.days)
    seq.mailing :subscription_ended_email_45 do |mailing|
      mailing.title = "Subscription ended 45 days ago"
      mailing.absolute_delay = 75.days
      mailing.mailer_name = "UserMailer"
      mailing.enable
    end
  end

Question: Is maily_herald capable of handle conditionals to determine whether or not an email must be sent?
If not, what other alternatives I have to accomplish my goal?

Doesn't send devise's confirmation email

Seems like one_time_mailings don't work.
Sidekiq and paperboy are started

Screens:

image
17 minutes Ago? But stilll 'Scheduled'? Sounds wrong

image

Log says:

2016-07-05T16:17:15Z 13465 [Maily#app] DEBUG: Attempt to deliver email without schedule. No mail was sent: <User#3> Kristian Gerardsson ["[email protected]"], <MailyHerald::OneTimeMailing#1> <OneTimeMailing: Confirmation Instructions>

Without schedule? It has mailing.start_at = Proc.new { |user| user.created_at } exactly copied from the wiki page.

What am I missing? (PS: AD HOC emails work fine)

uninitialized constant MailyHerald::Webui::Breadcrumbs

Screen Shot 2021-12-06 at 12 17 49 PM

ruby 2.7.4
rails 6.0.0

    maily_herald (0.9.4)
      liquid (> 2.6.1)
      rails (> 3.2)
      sidekiq
    maily_herald-webui (0.9.0)
      coffee-rails
      haml
      maily_herald (~> 0.9.2)
      sass-rails
      smart_listing (~> 1.1.0)

Stack trace:

maily_herald-webui (0.9.0) app/controllers/maily_herald/webui/application_controller.rb:4:in `<class:ApplicationController>'
maily_herald-webui (0.9.0) app/controllers/maily_herald/webui/application_controller.rb:3:in `<module:Webui>'
maily_herald-webui (0.9.0) app/controllers/maily_herald/webui/application_controller.rb:2:in `<module:MailyHerald>'
maily_herald-webui (0.9.0) app/controllers/maily_herald/webui/application_controller.rb:1:in `<main>'
bootsnap (1.4.6) lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
bootsnap (1.4.6) lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
bootsnap (1.4.6) lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
bootsnap (1.4.6) lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
bootsnap (1.4.6) lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
skylight-core (4.3.0) lib/skylight/core/probes.rb:118:in `require'
zeitwerk (2.3.0) lib/zeitwerk/kernel.rb:16:in `require'
maily_herald-webui (0.9.0) app/controllers/maily_herald/webui/dashboard_controller.rb:2:in `<module:MailyHerald>'
maily_herald-webui (0.9.0) app/controllers/maily_herald/webui/dashboard_controller.rb:1:in `<main>'
bootsnap (1.4.6) lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
bootsnap (1.4.6) lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
bootsnap (1.4.6) lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
bootsnap (1.4.6) lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
bootsnap (1.4.6) lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
skylight-core (4.3.0) lib/skylight/core/probes.rb:118:in `require'
zeitwerk (2.3.0) lib/zeitwerk/kernel.rb:16:in `require'
activesupport (6.0.2.2) lib/active_support/inflector/methods.rb:284:in `const_get'
activesupport (6.0.2.2) lib/active_support/inflector/methods.rb:284:in `block in constantize'
activesupport (6.0.2.2) lib/active_support/inflector/methods.rb:280:in `each'
activesupport (6.0.2.2) lib/active_support/inflector/methods.rb:280:in `inject'
activesupport (6.0.2.2) lib/active_support/inflector/methods.rb:280:in `constantize'
activesupport (6.0.2.2) lib/active_support/dependencies/zeitwerk_integration.rb:19:in `constantize'
actionpack (6.0.2.2) lib/action_dispatch/http/request.rb:88:in `controller_class_for'
actionpack (6.0.2.2) lib/action_dispatch/http/request.rb:81:in `controller_class'
actionpack (6.0.2.2) lib/action_dispatch/routing/route_set.rb:45:in `controller'
actionpack (6.0.2.2) lib/action_dispatch/routing/route_set.rb:31:in `serve'
actionpack (6.0.2.2) lib/action_dispatch/journey/router.rb:49:in `block in serve'
actionpack (6.0.2.2) lib/action_dispatch/journey/router.rb:32:in `each'
actionpack (6.0.2.2) lib/action_dispatch/journey/router.rb:32:in `serve'
actionpack (6.0.2.2) lib/action_dispatch/routing/route_set.rb:837:in `call'
skylight-core (4.3.0) lib/skylight/core/probes/action_dispatch/routing/route_set.rb:14:in `block in call'
skylight-core (4.3.0) lib/skylight/core/fanout.rb:25:in `instrument'
skylight-core (4.3.0) lib/skylight/core/probes/action_dispatch/routing/route_set.rb:13:in `call'
railties (6.0.2.2) lib/rails/engine.rb:526:in `call'
railties (6.0.2.2) lib/rails/railtie.rb:190:in `public_send'
railties (6.0.2.2) lib/rails/railtie.rb:190:in `method_missing'
actionpack (6.0.2.2) lib/action_dispatch/routing/mapper.rb:19:in `block in <class:Constraints>'
actionpack (6.0.2.2) lib/action_dispatch/routing/mapper.rb:48:in `serve'
actionpack (6.0.2.2) lib/action_dispatch/journey/router.rb:49:in `block in serve'
actionpack (6.0.2.2) lib/action_dispatch/journey/router.rb:32:in `each'
actionpack (6.0.2.2) lib/action_dispatch/journey/router.rb:32:in `serve'
actionpack (6.0.2.2) lib/action_dispatch/routing/route_set.rb:837:in `call'
skylight-core (4.3.0) lib/skylight/core/probes/action_dispatch/routing/route_set.rb:14:in `block in call'
skylight-core (4.3.0) lib/skylight/core/fanout.rb:25:in `instrument'
skylight-core (4.3.0) lib/skylight/core/probes/action_dispatch/routing/route_set.rb:13:in `call'
rack (2.2.2) lib/rack/tempfile_reaper.rb:15:in `call'
rack (2.2.2) lib/rack/etag.rb:27:in `call'
rack (2.2.2) lib/rack/conditional_get.rb:27:in `call'
rack (2.2.2) lib/rack/head.rb:12:in `call'
actionpack (6.0.2.2) lib/action_dispatch/http/content_security_policy.rb:18:in `call'
rack (2.2.2) lib/rack/session/abstract/id.rb:266:in `context'
rack (2.2.2) lib/rack/session/abstract/id.rb:260:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/cookies.rb:648:in `call'
activerecord (6.0.2.2) lib/active_record/migration.rb:567:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
activesupport (6.0.2.2) lib/active_support/callbacks.rb:101:in `run_callbacks'
actionpack (6.0.2.2) lib/action_dispatch/middleware/callbacks.rb:26:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/actionable_exceptions.rb:17:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/debug_exceptions.rb:32:in `call'
web-console (4.0.1) lib/web_console/middleware.rb:132:in `call_app'
web-console (4.0.1) lib/web_console/middleware.rb:28:in `block in call'
web-console (4.0.1) lib/web_console/middleware.rb:17:in `catch'
web-console (4.0.1) lib/web_console/middleware.rb:17:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
railties (6.0.2.2) lib/rails/rack/logger.rb:38:in `call_app'
railties (6.0.2.2) lib/rails/rack/logger.rb:26:in `block in call'
activesupport (6.0.2.2) lib/active_support/tagged_logging.rb:80:in `block in tagged'
activesupport (6.0.2.2) lib/active_support/tagged_logging.rb:28:in `tagged'
activesupport (6.0.2.2) lib/active_support/tagged_logging.rb:80:in `tagged'
railties (6.0.2.2) lib/rails/rack/logger.rb:26:in `call'
sprockets-rails (3.2.1) lib/sprockets/rails/quiet_assets.rb:13:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/request_id.rb:27:in `call'
skylight-core (4.3.0) lib/skylight/core/probes/action_dispatch/request_id.rb:12:in `call'
rack (2.2.2) lib/rack/method_override.rb:24:in `call'
rack (2.2.2) lib/rack/runtime.rb:22:in `call'
activesupport (6.0.2.2) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/static.rb:126:in `call'
rack (2.2.2) lib/rack/sendfile.rb:110:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/host_authorization.rb:83:in `call'
honeybadger (4.6.0) lib/honeybadger/rack/error_notifier.rb:33:in `block in call'
honeybadger (4.6.0) lib/honeybadger/agent.rb:399:in `with_rack_env'
honeybadger (4.6.0) lib/honeybadger/rack/error_notifier.rb:30:in `call'
honeybadger (4.6.0) lib/honeybadger/rack/user_feedback.rb:31:in `call'
honeybadger (4.6.0) lib/honeybadger/rack/user_informer.rb:21:in `call'
webpacker (5.1.1) lib/webpacker/dev_server_proxy.rb:25:in `perform_request'
rack-proxy (0.6.5) lib/rack/proxy.rb:57:in `call'
railties (6.0.2.2) lib/rails/engine.rb:526:in `call'
rack (2.2.2) lib/rack/handler/webrick.rb:95:in `service'
/Users/grace/.rbenv/versions/2.7.4/lib/ruby/2.7.0/webrick/httpserver.rb:140:in `service'
/Users/grace/.rbenv/versions/2.7.4/lib/ruby/2.7.0/webrick/httpserver.rb:96:in `run'
/Users/grace/.rbenv/versions/2.7.4/lib/ruby/2.7.0/webrick/server.rb:307:in `block in start_thread' 

ng: ActionMailer is called statically

When a ActionMailer is defined, it should be instantiated before being called. Instead it is called statically, resulting in the following error:

---
:msg: |-
  protected method `process' called for #<HelloMailer:0x00007fc2edb0e368>

  $HOME/.rvm/gems/ruby-2.5.3/gems/actionmailer-6.0.3.2/lib/action_mailer/message_delivery.rb:124:in `block in processed_mailer'
  $HOME/.rvm/gems/ruby-2.5.3/gems/actionmailer-6.0.3.2/lib/action_mailer/message_delivery.rb:123:in `tap'
  $HOME/.rvm/gems/ruby-2.5.3/gems/actionmailer-6.0.3.2/lib/action_mailer/message_delivery.rb:123:in `processed_mailer'
  $HOME/.rvm/gems/ruby-2.5.3/gems/actionmailer-6.0.3.2/lib/action_mailer/message_delivery.rb:30:in `__getobj__'
  $HOME/.rvm/rubies/ruby-2.5.3/lib/ruby/2.5.0/delegate.rb:80:in `method_missing'
  $HOME/.rvm/gems/ruby-2.5.3/bundler/gems/maily_herald-bd3ec31974c0/app/models/maily_herald/mailing.rb:194:in `deliver'
  $HOME/.rvm/gems/ruby-2.5.3/bundler/gems/maily_herald-bd3ec31974c0/app/models/maily_herald/one_time_mailing.rb:19:in `block in run'
  $HOME/.rvm/gems/ruby-2.5.3/gems/activerecord-6.0.3.2/lib/active_record/relation/delegation.rb:87:in `each'
  $HOME/.rvm/gems/ruby-2.5.3/gems/activerecord-6.0.3.2/lib/active_record/relation/delegation.rb:87:in `each'
  $HOME/.rvm/gems/ruby-2.5.3/bundler/gems/maily_herald-bd3ec31974c0/app/models/maily_herald/one_time_mailing.rb:17:in `collect'
  $HOME/.rvm/gems/ruby-2.5.3/bundler/gems/maily_herald-bd3ec31974c0/app/models/maily_herald/one_time_mailing.rb:17:in `run'
  $HOME/.rvm/gems/ruby-2.5.3/bundler/gems/maily_herald-bd3ec31974c0/lib/maily_herald/manager.rb:25:in `block in run_all'
  $HOME/.rvm/gems/ruby-2.5.3/gems/activerecord-6.0.3.2/lib/active_record/relation/delegation.rb:87:in `each'
  $HOME/.rvm/gems/ruby-2.5.3/gems/activerecord-6.0.3.2/lib/active_record/relation/delegation.rb:87:in `each'
  $HOME/.rvm/gems/ruby-2.5.3/bundler/gems/maily_herald-bd3ec31974c0/lib/maily_herald/manager.rb:25:in `run_all'
  $HOME/.rvm/gems/ruby-2.5.3/bundler/gems/maily_herald-bd3ec31974c0/lib/maily_herald.rb:31:in `perform'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/processor.rb:196:in `execute_job'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/processor.rb:164:in `block (2 levels) in process'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/middleware/chain.rb:138:in `block in invoke'
  $HOME/.rvm/gems/ruby-2.5.3/gems/rollbar-2.26.0/lib/rollbar/plugins/sidekiq/plugin.rb:11:in `call'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/middleware/chain.rb:140:in `block in invoke'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/middleware/chain.rb:143:in `invoke'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/processor.rb:163:in `block in process'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/processor.rb:136:in `block (6 levels) in dispatch'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/job_retry.rb:111:in `local'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/processor.rb:135:in `block (5 levels) in dispatch'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/rails.rb:14:in `block in call'
  $HOME/.rvm/gems/ruby-2.5.3/gems/activesupport-6.0.3.2/lib/active_support/execution_wrapper.rb:88:in `wrap'
  $HOME/.rvm/gems/ruby-2.5.3/gems/activesupport-6.0.3.2/lib/active_support/reloader.rb:72:in `block in wrap'
  $HOME/.rvm/gems/ruby-2.5.3/gems/activesupport-6.0.3.2/lib/active_support/execution_wrapper.rb:88:in `wrap'
  $HOME/.rvm/gems/ruby-2.5.3/gems/activesupport-6.0.3.2/lib/active_support/reloader.rb:71:in `wrap'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/rails.rb:13:in `call'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/processor.rb:131:in `block (4 levels) in dispatch'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/processor.rb:257:in `stats'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/processor.rb:126:in `block (3 levels) in dispatch'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/job_logger.rb:13:in `call'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/processor.rb:125:in `block (2 levels) in dispatch'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/job_retry.rb:78:in `global'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/processor.rb:124:in `block in dispatch'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/logger.rb:10:in `with'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/job_logger.rb:33:in `prepare'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/processor.rb:123:in `dispatch'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/processor.rb:162:in `process'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/processor.rb:78:in `process_one'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/processor.rb:68:in `run'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/util.rb:15:in `watchdog'
  $HOME/.rvm/gems/ruby-2.5.3/gems/sidekiq-6.1.1/lib/sidekiq/util.rb:24:in `block in safe_thread'

Throttle email sending

Hi, I want to use maily_herald with Amazon SES, I have some limitations when sending email like send 50000 emails per 24 hour period and a send rate of 14 emails/second.

is possible to throttle email sending? so I can set it to send 14 emails per second, and also set the limit of 50000 each 24 hours.

I added the feature in the readme #4

where should be the starting point for this feature? and would be great too if the configs could be set from the webui.

Periodical mailings tests failing

Hi, today I pulled from your master and ran tests, this one is failing, Travis should show the build failing:

Failed examples:

rspec ./spec/models/maily_herald/periodical_mailing_spec.rb:116 # MailyHerald::PeriodicalMailing Periodical Delivery should deliver mailings periodically

Test was passing before d904758

Html One Time Mailings Template

I started using you gem, and i wanted to know how can i send HTML email? Since everything i send using the Generic mailer is sent as plain text.

Thanks in advance!

Mail delivery stops after some time

Hello there,

First of all, thank you for programming and making maily_herald available to everyone.

I am having this problem, where mail delivery stops on its own. I am not sure if it is after a number of emails sent or after a specific amount of time. My mailing list has around 3300 emails in total, and I have noticed that mail delivery stops after about 2000 emails have been sent out (or appr. after 20 minutes since start of mailing). This has now happened twice in a row. I do not seem to have this problem with shorter mailing lists. If I stop and then re-start the Rails app, then delivery resumes and finishes without further issues.

Processes, like redis, sidekiq and paperboy, seem to be running and I cannot seem to find anything relevant in my logs.

Any ideas?

Many thanks in advance.

How to start GUI?

Just installed MH for a test spin. How do I run it/set it up?

$ maily_herald 
uninitialized constant #<Class:MailyHerald>::Pathname
/var/lib/gems/2.5.0/gems/maily_herald-0.9.4/lib/maily_herald.rb:387:in `read_options'
/var/lib/gems/2.5.0/gems/maily_herald-0.9.4/lib/maily_herald/cli.rb:99:in `setup_options'
/var/lib/gems/2.5.0/gems/maily_herald-0.9.4/lib/maily_herald/cli.rb:15:in `parse'
/var/lib/gems/2.5.0/gems/maily_herald-0.9.4/bin/maily_herald:9:in `<top (required)>'
/usr/local/bin/maily_herald:23:in `load'
/usr/local/bin/maily_herald:23:in `<main>'

Sorry, not a Ruby on Rails user... is the software too young for general users?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.