Rails cron not sending emails - ruby-on-rails

I'm using the whenever gem to have a rails cron job send emails. Everything seems to work just fine and i have no errors in my cron.log or my production.log file, but i never receive an email. I've checked that the email address is correct also.
Any help is appreciated.
The production.log file contains this:
Connecting to database specified by database.yml
Rendered email_mailer/send_birthday_reminders.html.erb (5.3ms)
Sent mail to tomcaflisch#gmail.com (409ms)
Here's my whenever gem schedule.rb file
set :output, "#{path}/log/cron.log"
every :hour do
runner "BirthdayRemindersController.send_birthday_email_reminders"
end
birthday_reminders_controller.rb
class BirthdayRemindersController < ApplicationController
# cron job that sends birthday reminders
def self.send_birthday_email_reminders
users = User.all
email_addresses = []
users.each_with_index do |user, i|
if user.user_details.birthday_reminders == true
email_addresses[i] = get_primary_email(user)
end
end
p "email_addresses to send to:"
p email_addresses
users.each do |user|
p "this user is"
p user.user_details.full_name
if user.user_details.birthday.try(:strftime, "%m") == Date.today.strftime("%m") && user.user_details.birthday.try(:strftime, "%d") == Date.today.strftime("%d")
p "reminder sent"
EmailMailer.send_birthday_reminders(user, email_addresses).deliver
end
end
end
end
email_mailer.rb snippet
class EmailMailer < ActionMailer::Base
include ApplicationHelper
default :from => "\"FamNFo\" <no-reply#mysite.com>"
def send_birthday_reminders(birthday_person, email_addresses)
p "we in send_birthday_reminders mailer"
p email_addresses
#birthday_person = birthday_person
mail(:subject => "Birthday Reminder For The Caflisch Family", :to => email_addresses, :reply_to => email_addresses)
end
end
capistrano's deploy.rb contains this
# needed for the 'whenever' gem
set(:whenever_command) { "RAILS_ENV=#{rails_env} bundle exec whenever"}
require "whenever/capistrano"

Check your spam folder. To make sure emails don't end up there, add an "Unsubscribe" link in each email.

This could happen if your action mailer configuration specifies perform_deliveries=false. You can check out the configuration in your environment files.

If your application is deployed to cloud services then you may be getting your emails in a spam folder. Their entire IP blocks are registered as spam at services like Spamhaus, which is a sensible precaution or else we'd be getting even more spam than usual.
You should enter your server's IP address in that field to see if you're listed as a spammer.
If you are, you can request to Spamhaus that the block be lifted.

The other big issues I have found is that the PATH and rbenv may not be initialized in the CRONTAB depending on how you have it setup.
I would recommend adding the following to the top of your .bashrc file
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
This ensures that if you are using whenever to call model methods that rbenv and ruby are fully available.

Related

Rails - conditionally log for a specific hostname

I'm looking for a way to configure a Rails server log only if the client has contacted a specific hostname. e.g. I could make it so that http://public.example.com doesn't get logged, but http://debug.example.com (same underlying Rails app server) does get logged (or ideally gets logged in more detail than the regular host). It would help with production debugging.
You can use gem Lograge to customize your log. This gem will give you much more custom to your log. For example, in your case, I will do this
After install the gem. Create a file at config/initializers/lograge.rb
# config/initializers/lograge.rb
Rails.application.configure do
config.lograge.enabled = true
config.lograge.custom_options = lambda do |event|
# custom log on specific domain
if event.payload[:host] == "debug.example.com"
{:host => event.payload[:host]}
else
{}
end
end
end
And in your Application Controller
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
# This will add request's host to lograge so you can use it to filter log later
def append_info_to_payload(payload)
super
payload[:host] = request.host
end
end
Now you can customize your log base on domain, on how to customize it please read at: https://github.com/roidrage/lograge

Heroku timeout when sending emails

I am on Heroku with a custom domain, and I have the Redis add-on. I need help understanding how to create a background worker for email notifications. Users can inbox message each other, and I would like to send a email notification to the user for each new message received. I have the notifications working in development, but I am not good with creating background jobs which is required for Heroku, otherwise the server would timeout.
Messages Controller:
def create
#recipient = User.find(params[:user])
current_user.send_message(#recipient, params[:body], params[:subject])
flash[:notice] = "Message has been sent!"
if request.xhr?
render :json => {:notice => flash[:notice]}
else
redirect_to :conversations
end
end
User model:
def mailboxer_email(object)
if self.no_email
email
else
nil
end
end
Mailboxer.rb:
Mailboxer.setup do |config|
#Configures if you applications uses or no the email sending for Notifications and Messages
config.uses_emails = false
#Configures the default from for the email sent for Messages and Notifications of Mailboxer
config.default_from = "no-reply#domain.com"
#Configures the methods needed by mailboxer
config.email_method = :mailboxer_email
config.name_method = :name
#Configures if you use or not a search engine and which one are you using
#Supported enignes: [:solr,:sphinx]
config.search_enabled = false
config.search_engine = :sphinx
end
Sidekiq is definitely the way to go with Heroku. I don't think mailboxer supports background configuration out of the box. Thankfully, it's still really easy with sidekiq's queueing process.
Add gem 'sidekiq' to your gemfile and run bundle.
Create a worker file app/workers/message_worker.rb.
class MessageWorker
include Sidekiq::Worker
def perform(sender_id, recipient_id, body, subject)
sender = User.find(sender_id)
recipient = User.find(recipient_id)
sender.send_message(recipient, body, subject)
end
end
Update your Controller to Queue Up the Worker
Remove: current_user.send_message(#recipient, params[:body], params[:subject])
Add: MessageWorker.perform_async(current_user.id, #recipient.id, params[:body], params[:subject])
Note: You should never pass workers ActiveRecord objects. That's why I setup this method to pass the User ids and look them up in the worker's perform method, instead of the entire object.
Finally, restart your server and run bundle exec sidekiq. Now your app should be sending the email background.
When you deploy, you will need a separate dyno for the worker which should look like this: worker: bundle exec sidekiq. You will also need Heroku's redis add-on.
Sounds like a H21 Request Timeout:
An HTTP request took longer than 30 seconds to complete.
To create a background worker for this in RoR, you should grab Resque, a Redis-backed background queueing library for RoR. Here is a demo. Another demo. And another demo.
To learn more about using Resque in Heroku, you can also read the herokue article up here. Or this tutorial (it's an old one though). Another great tutorial.
There is also a resque_mailer gem that will speed things up for you.
gem install resque_mailer #or add it to your Gemfile & use bundler
It is fairly straightforward. Here is a snippet from a working demo by the author:
class Notifier < ActionMailer::Base
include Resque::Mailer
default :from => "from#example.com"
def test(data={})
data.symbolize_keys!
Rails.logger.info "sending test mail"
Rails.logger.info "params: #{data.keys.join(',')}"
Rails.logger.info ""
#subject = data[:subject] || "Testing mail"
mail(:to => "nap#localhost.local",
:subject => #subject)
end
end
doing Notifier.test.deliver will deliver the mail.
You can also consider using mail delivery services like SES.
Sidekiq is an option that you could consider. To get it working you can add something like RedisToGo, then configure an initializer for Redis. Then on Heroku you can add something like worker: bundle exec sidekiq ... to your Procfile.
https://github.com/mperham/sidekiq/wiki/Getting-Started
It also has a dashboard for monitoring.
https://github.com/mperham/sidekiq/wiki/Monitoring

Update activerecords in faye event listeners

I am writing a rails app which requires to track users' status to see if they are available, busy or offline. I'm using the private_pub gem, which uses Faye underneath. When a user signs in he subscribes to a channel /user/[:user_id]. I want to update user's status to ONLINE when they subscribe using Faye's subscribe event listener. I added this code at the end of private_pub.ru file:
server = PrivatePub.faye_app
server.bind :subscribe do |client_id, channel|
if /\/user\/*/.match(channel)
m = /\/user\/(?<user_id>\d+)/.match(channel)
user_id = m[:user_id]
end
user = User.find(user_id)
user.status = 1 # 1 means online
end
run server
The problem is every time a user subscribes, thin server reports:
[ERROR] [Faye::RackAdapter] uninitialized constant User
I guess I need to require certain files to be able to use activerecords in the rackup file. But I don't know how.
Thanks for any help.
In our project we decide to use redis for similar case.
Gemfile:
gem 'redis-objects'
Faye: use redis-rb for writing status
require 'redis'
Redis.current = Redis.new(:host => '127.0.0.1', :port => 6379)
# init faye server
...
server.bind(:subscribe) do |client_id, channel|
if /\/user\/*/.match(channel)
m = /\/user\/(?<user_id>\d+)/.match(channel)
Redis.current.set("user:#{m[:user_id]}:online_status", "1")
end
end
Rails: use redis-objects gem for reading it in User's model.
class User < ActiveRecord::Base
include Redis::Objects
value :online_status
end
#user.online_status # returns "1" if channel is connected
Hope this helps.

Prevent Rails from logging email attachments

When I send an email with an attachment the data is logged in hex and fills up my whole log. Is there a way to disable logging of attachments?
I know I can disable mailer logging with config.action_mailer.logger = nil.
Unfortunately, the attachments are included in the logs if the logging level is set to :debug, the default level for non-production environments. This means that in production you should be fine, but your dev and staging environments could bloat during testing. You could turn down logging for your entire app (config.log_level = :info), but this is obviously less than ideal.
You can configure a custom logger:
config.action_mailer.logger = ActiveSupport::BufferedLogger.new("mailer.log")
config.action_mailer.logger.level = ActiveSupport::BufferedLogger::Severity::INFO
Rails 4
config.action_mailer.logger = ActiveSupport::Logger.new("mailer.log")
config.action_mailer.logger.level = ActiveSupport::Logger::Severity::INFO
This will split the log, but you can isolate the logging level change to the action mailer.
If you still want your log level to be debug, you can remove the attachments from the log output by overriding ActionMailer's LogSubscriber class. Look at the class in your actionmailer gem, and adjust accordingly. For my Rails 4.2.10 install, the relevant file is:
gems/actionmailer-4.2.10/lib/action_mailer/log_subscriber.rb
My module is:
module ActionMailer
class LogSubscriber < ActiveSupport::LogSubscriber
def deliver(event)
info do
recipients = Array(event.payload[:to]).join(', ')
"\nSent mail to #{recipients}, Subject: #{event.payload[:subject]}, on #{event.payload[:date]} (#{event.duration.round(1)}ms)"
end
debug { remove_attachments(event.payload[:mail]) }
end
def remove_attachments(message)
new_message = ''
skip = false
message.each_line do |line|
new_message << line unless skip
skip = true if line =~ /Content-Disposition: attachment;/
skip = false if skip && line =~ /----==_mimepart/
end
new_message
end
end
end
Save this to an .rb file anywhere under your app/ folder and it will be included.
in Application.rb you could try filtering the attachment parameter. I believe this should solve the issue, but I have not tested it myself
config.filter_parameters += [:attachment]

ar_sendmail command not working with ruby 1.9.2

I am not able to run ar_sendmail command from my terminal. I don't think i have missed its configuration. Below is my code;
development.rb
++++++++++++++++++++++++++++++++++++++++++++++++++++
ActionMailer::Base.delivery_method = :activerecord
ActionMailer::Base.smtp_settings = {
:address => "smtp.gmail.com",
:port => 25,
:domain => "www.google.com",
:authentication => :plain,
:user_name => "ashis.lun#gmail.com",
:password => "kathmandu",
:enable_starttls_auto => true
}
require "action_mailer/ar_mailer"
Gemfile
+++++++++++++++++++++++++++
gem "ar_mailer", "1.5.1"
My Mailer
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
class Postoffice &lt ActionMailer::ARMailer
def recover_password_email(account, name, address)
#recipients = address
#from = "ashis.lun#gmail.com"
#subject = "Your Account at #{account.org_name} is Ready"
#body["subdomain"] = account.subdomain
#body["name"] = name
#body["org_name"] = account.org_name
#body["password"] = password
#body["email"] = address
end
end
My controller
++++++++++++++++++++++++++++++++++++++++++++++++++++
def reset_password
#user = User.find_by_email(params[:email])
begin
if #user
password = get_new_password
#user.update_attributes!(:password => password)
Postoffice.deliver_recover_password_email(#account, #user.individual.firstname, #user.email, password)
flash[:notice] = "Your password has been e-mailed to you. It should show up in a minute!"
redirect_to '/sessions/new'
end
rescue
flash[:notice] = "Sorry, there was a problem resetting your password."
redirect_to '/sessions/new'
end
end
end
Whenever I run ar_sendmail command I just get below message. If i hit RAILS_ROOT in console then I it shows /Users/me/Dev/a5his
Usage: ar_sendmail [options]
ar_sendmail scans the email table for new messages and sends them to the
website's configured SMTP host.
ar_sendmail must be run from a Rails application's root or have it specified
with --chdir.
If ar_sendmail is started with --pid-file, it will fail to start if the PID
file already exists or the contents don't match it's PID.
Sendmail options:
-b, --batch-size BATCH_SIZE Maximum number of emails to send per delay
Default: Deliver all available emails
--delay DELAY Delay between checks for new mail
in the database
Default: 60
--max-age MAX_AGE Maxmimum age for an email. After this
it will be removed from the queue.
Set to 0 to disable queue cleanup.
Default: 604800 seconds
-o, --once Only check for new mail and deliver once
Default: false
-p, --pid-file [PATH] File to store the pid in.
Defaults to /var/run/ar_sendmail.pid
when no path is given
-d, --daemonize Run as a daemon process
Default: false
--mailq Display a list of emails waiting to be sent
Setup Options:
--create-migration Prints a migration to add an Email table
to stdout
--create-model Prints a model for an Email ActiveRecord
object to stdout
Generic Options:
-c, --chdir PATH Use PATH for the application path
Default: .
-e, --environment RAILS_ENV Set the RAILS_ENV constant
Default:
-t, --table-name TABLE_NAME Name of table holding emails
Used for both sendmail and
migration creation
Default: Email
-v, --[no-]verbose Be verbose
Default:
-h, --help You're looking at it
ar_sendmail must be run from a Rails application's root to deliver email.
/Users/me/Dev/a5his does not appear to be a Rails application root.
Thanks in advance <><
How about using Delayed Job? I've used ar mailer in the past and find delayed job a much better solution.
https://github.com/collectiveidea/delayed_job
Not sure if it'll make a difference, but it says here to put
require "action_mailer/ar_mailer"
in environment.rb, not development.rb or production.rb. Other than that, I can't see anything you missed.
Try ar_sendmail --chdir /Users/me/Dev/a5his or changing into the root of your rails app before running the command
ar_sendmail must be run from a Rails application's root to deliver email.
/Users/me/Dev/a5his does not appear to be a Rails application root.
Are you running the command in the application's root?
try
cd #{Rails.root.to_s} && bundle exec ar_sendmail_rails3 -e production
If you look at the source (shown below), this message is displayed if loading config/environment fails. One instance of this I ran into was where a dependency was unmet, which was causing an exception to fire when config/environment was being loaded. To address this, you can use an irb session and try requiring config/environment to see what error may be causing the require to fail.
Dir.chdir options[:Chdir] do
begin
require 'config/environment'
rescue LoadError
usage opts, <<-EOF
#{name} must be run from a Rails application's root to deliver email.
#{Dir.pwd} does not appear to be a Rails application root.
EOF
end
end

Resources