ROR sending email based on account number - ruby-on-rails

We're using Ruby 1.9 and Rails 3.2 We use AS/400 for our database. We've tried using Active Record for this before, and it doesn't want to work because of our versions of Ruby and Rails being older combined with getting it to connect with the 400.
We have an online ordering site that you have to have an account set up to access. Depending on what type of account you are set up as, you might have to have your order approved by someone. I.e. if I am a drop ship account, my distributor has to approve what I'm ordering. The way it had been set up, the distributor wasn't getting any kind of approval email.
We've been trying the line of code below in console, and have it working. If we enter an account number instead of leaving it blank, it returns a list of the email addresses that would be getting the approval email. Fantastic! If it's left blank as shown below, it returns a blank array. Makes sense, we haven't logged in, so it doesn't know our account number yet. When the user logs in, their account number should automatically be substituted in.
Contact.find_by_sql ["SELECT EMAL23 FROM WEBOEL23 WHERE ACT223 = ‘’”]
However, when we add that code snippet into the order.rb file, it returns an error:
wrong number of arguments (1 for 4)
Clearly, the way we have the line set up isn't right:
Mailer.deliver_order_distributor_approval_email('Contact.find_by_sql (SELECT EMAL23 FROM WEBOEL23 WHERE ACT223 = "30153"')
It's just getting confusing... we seem to be going in circles with the errors. We try to fix it, but then we just get new errors that still have to do with that line.
The deliver_order_distributor_approval_email method is in the mailer.rb file below:
class Mailer < ActionMailer::Base
##################################################################################
##################################################################################
# NOTE: in all cases, use sanitize_email to ensure nothing goes out by accident. #
##################################################################################
##################################################################################
def order_confirmation_email(recipient_email, from_email, subject, email_details)
recipient_email = Mailer.sanitize_email(recipient_email)
# Get the template of the email body from the database and then perform all replacements.
email_body = Setting.first.email_order_body
email_details.each {|key, value| email_body.gsub!("##" + key.upcase.gsub("_"," ") + "##", value)}
recipients recipient_email
from from_email
subject subject
bcc Setting.first[:email_admin_to]
part :content_type => "text/html",
:body => email_body
#f=File.open("/var/www/onlineordering.example.com/log/debugger.txt")
#f.puts get_email = $get_email
#f.close
end
def order_coastal_notify_email(from_email, subject, email_details)
# Get the template of the email body from the database and then perform all replacements.
email_body = Setting.first.email_order_coastal_notify
email_details.each {|key, value| email_body.gsub!("##" + key.upcase.gsub("_"," ") + "##", value)}
recipients Setting.first[:email_order_placed_to]
from from_email
subject subject
bcc Setting.first[:email_admin_to]
part :content_type => "text/html",
:body => email_body
end
def order_distributor_approval_email(recipient_email, from_email, subject, email_details)
recipient_email = Mailer.sanitize_email(recipient_email)
# Get the template of the email body from the database and then perform all replacements.
# We run the attachment and the email body through replacement tags.
email_body = Setting.first.email_order_attachment_body
email_attachment_body = Setting.first.email_order_attachment
email_details.each {|key, value| email_body.gsub!("##" + key.upcase.gsub("_"," ") + "##", value)}
email_details.each {|key, value| email_attachment_body.gsub!("##" + key.upcase.gsub("_"," ") + "##", value)}
# If their email is blank, we'll send it to admin.
recipients recipient_email.blank? ? Setting.first[:email_admin_to] : recipient_email
from from_email
subject subject
bcc Setting.first[:email_order_placed_to]
part :content_type => "text/html",
:body => email_body
attachment "application/pdf" do |a|
a.body = WickedPdf.new.pdf_from_string(email_attachment_body)
a.filename = "Drop Ship Approval Form.pdf"
end
end
def order_again_reminder_email(name, recipient_email, from_email, subject)
recipient_email = Mailer.sanitize_email(recipient_email)
recipients recipient_email
from from_email
bcc Setting.first[:email_admin_to]
subject subject
body :content => Setting.first.email_reminder_body.gsub!(/##NAME##/, name.to_s.titleize)
end
def forgot_password_email(recipient_email, from_email, subject, password)
recipient_email = Mailer.sanitize_email(recipient_email)
recipients recipient_email
from from_email
bcc Setting.first[:email_admin_to]
subject subject
body :password => password
end
def register_email(recipient_email, from_email, subject, params)
recipient_email = Mailer.sanitize_email(recipient_email)
recipients recipient_email
from from_email
bcc Setting.first[:email_admin_to]
subject subject
body :params => params
end
private
def self.sanitize_email(recipient_email)
# Comma separate multiple email addresses.
case ENV['RAILS_ENV']
when 'production'
recipient_email = recipient_email
when 'development'
recipient_email = "John Doe<john#example.com>"
else
# This is really the production, since they don't have a true production server
# should resolve to "dev".
recipient_email = recipient_email
end
recipient_email
end
end
If the order.rb file would be helpful, I can attach it... it's just kind of lengthy, so I didn't include it in the post. If you have any suggestions as to how to change the mailer.deliver_order_distributor_approval_email line, please let me know.. I'd really appreciate it! Thank you in advance!
Edit
Mailer.deliver_order_distributor_approval_email ('Contact.find_by_sql SELECT EMAL23 FROM WEBOEL23 WHERE ACT223 = "30153"'),"Coastal Pet Online Ordering<noreply#coastalpet.com>", "Order Confirmation-customer", email_details
With this (after some tweaking), we were able to submit an order without any errors, but we aren't getting any emails. Odd. It almost seems like we might be missing some mailer calls or something?
Edit
After modifying the script suggested a little, we came up with this...
target_email = Contact.find_by_sql ["SELECT EMAL23 FROM WEBOEL23 WHERE ACT223 = ''"]
Mailer.deliver_order_confirmation_email(target_email, "Coastal Pet Online Ordering<noreply#coastalpet.com>", "Order Confirmation-customer", email_details)
It "works" without errors - we can log in and submit an order, but still fail to get any email.
Oddly enough, that snippet returns the error below when ran through the console.
ActiveRecord::StatementInvalid: 37000 (-10) [IBM][iSeries Access ODBC Driver][DB 2 UDB]SQL0010 - String constant beginning ' ' not delimited.
If we put in an account number like below, it runs through and submits.. but still no email. It returns an error on the console, too.
target_email = Contact.find_by_sql ["SELECT EMAL23 FROM WEBOEL23 WHERE ACT223 ='30153'"]
Mailer.deliver_order_confirmation_email(target_email, "Coastal Pet Online Ordering<noreply#coastalpet.com>", "Order Confirmation-customer", email_details)
Error:
NameError: undefined local variable or method `email_details' for main:Object
Ideas?

The error message you are getting:
wrong number of arguments (1 for 4)
indicates that you have called a method that expects four arguments, but you only provided one. Here's your method call:
Mailer.deliver_order_distributor_approval_email('Contact.find_by_sql (SELECT EMAL23 FROM WEBOEL23 WHERE ACT223 = "30153"')
As written, you've provided one argument: the string 'Contact.find_by_sql (SELECT EMAL23 FROM WEBOEL23 WHERE ACT223 = "30153"'.
When you call the method Mailer.deliver_order_distributor_approval_email, it eventually passes the arguments it is given to the order_distributor_approval_email method you've defined in your Mailer class. That method requires four arguments, but you're only giving it one, hence the error. You need to provide all four arguments to make the method call work.
Update:
You are passing the string 'Contact.find_by_sql SELECT EMAL23 FROM WEBOEL23 WHERE ACT223 = "30153"' as the first argument, so the mailer is trying to treat that string as an email address, which naturally isn't going to work. Presumably you want to actually call the find_by_sql method on Contact to get the real email address, in which case you'll want something like this:
target_email = Contact.find_by_sql('SELECT EMAL23 FROM WEBOEL23 WHERE ACT223 = "30153"').first
Mailer.deliver_order_distributor_approval_email(target_email, "Coastal Pet Online Ordering<noreply#coastalpet.com>", "Order Confirmation-customer", email_details)
This should perform the query and attempt to send the email to the first result. You will need to make further adjustments to send to multiple recipients or to send multiple emails.

Related

How to filter out inactive emails from an array of emails in a rails application?

I am currently working on a ticket where it asks me to filter out any inactive email to be sent to the recipient. Here is the method I am working on:
def self.delivering_email(message)
return if email_to_be_delivered?(message.subject)
email_list = message.to
if email_list.is_a?(String)
email_list = email_list.split(",").map(&:strip)
end
email_list.each { |email|
identity = Identity.find_by(email: email)
next if identity.nil?
# email_list.delete(email) unless identity.try(:preferred_user).active?
email_list.select(email) if identity.try(:preferred_user).active?
}
message.to = email_list
message.perform_deliveries = !email_list.empty?
end
the "# email_list.delete(email) unless identity.try(:preferred_user).active?" I commented out because the QA mentioned that ONLY one inactive email filters out and does not fully filter other inactive emails in the array. I assumed instead of .delete I have to use .select but don't know if it works because I don't have any way to test and reproduce the error on my end, or how to implement it the right way.
Any help will be appreciated.
You're trying to modify an array while you're iterating over it, that may lead to weird behavior. One option is to just use a separate array.
Since you are already iterating with email_list.each you can call next if the current email does not satisfy you, like you already do for identity.nil?.
So it may look smth like
valid_emails = []
email_list.each { |email|
identity = Identity.find_by(email: email)
next if identity.nil? || !identity.try(:preferred_user).active?
valid_emails << email
end
message.to = valid_emails

Official email validation in Ruby

I only want official email addresses such as xyz#company.com to sign up on my service rather than other generic email addresses such as gmail.com or Yahoo mail.com
Is there a ruby gem to achieve this kind of email validation? If not, how to make this happen?
You could write a custom validation in the appropriate model as shown here: http://www.rails-dev.com/custom-validators-in-ruby-on-rails-4
The basic idea in the article is as follows:
Make your validation method, and put it in a new directory called 'validators'
# app/validators/email_validator.rb
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value =~ /\A([^#\s]+)+#yourdomain.com\z/i
record.errors[attribute] << (options[:message] || "wrong email address")
end
end
end
(I have not tested this regex! Please use something like http://rubular.com/ and plug in your own email domain pattern to make sure it's working correctly.)
Then make sure Rails knows to load the new validators directory:
# config/application.rb
config.autoload_paths += %W["#{config.root}/app/validators/"]
Then add the new validation (email) to the appropriate model:
#MyModel.rb
validates :my_email_field, email: true
There is a free MailboxValidator web service that you can perform real-time email address validation in Ruby.
https://github.com/MailboxValidator/mailboxvalidator-ruby
require "mailboxvalidator_ruby"
apikey = "MY_API_KEY"
email = "example#example.com"
mbv = MailboxValidator::MBV.new()
mbv.apikey = apikey
mbv.query_single(email)
if mbv.error != nil
puts "Error: #{mbv.error}"
elsif mbv.result != nil
puts "email_address: #{mbv.result.email_address}"
puts "domain: #{mbv.result.domain}"
puts "is_free: #{mbv.result.is_free}"
puts "is_syntax: #{mbv.result.is_syntax}"
puts "is_domain: #{mbv.result.is_domain}"
puts "is_smtp: #{mbv.result.is_smtp}"
puts "is_verified: #{mbv.result.is_verified}"
puts "is_server_down: #{mbv.result.is_server_down}"
puts "is_greylisted: #{mbv.result.is_greylisted}"
puts "is_disposable: #{mbv.result.is_disposable}"
puts "is_suppressed: #{mbv.result.is_suppressed}"
puts "is_role: #{mbv.result.is_role}"
puts "is_high_risk: #{mbv.result.is_high_risk}"
puts "is_catchall: #{mbv.result.is_catchall}"
puts "mailboxvalidator_score: #{mbv.result.mailboxvalidator_score}"
puts "time_taken: #{mbv.result.time_taken}"
puts "status: #{mbv.result.status}"
puts "credits_available: #{mbv.result.credits_available}"
puts "error_code: #{mbv.result.error_code}"
puts "error_message: #{mbv.result.error_message}"
end

Send image inline in email using Rails 2

I am working on rails 2 application with sending email functionality. Now, I need to send inline image with the email.
I am using Mailer to send email. I tried lots of time using different ways but not succeed to send image inline in email. Below code i am using to send email.
# Controller
Mailer.delivery_my_opinion_reply(user, my_opinion, answer)
# Model / Mailer.rb
def my_opinion_reply(user, my_opinion, answer)
#subject = "My opinion"
#from = "#{Settings.site_name}"
#recipients = user.email
#content_type = "multipart/alternative"
#attachments.inline['test.jpg'] = File.read(RAILS_ROOT + "/public/system/att_images/728/original/ball1.jpg")
#body = {:question => my_question, :user => user}
end
I got error "undefined method inline for nil class"
try this way
#attachments.inline['image.png'] = File.read("app/assets/images/image.png")
mail(to: email, subject: "subject", content_type: "text/html")

Sending Simple Email in Rails

I've read a few questions and http://guides.rubyonrails.org/action_mailer_basics.html on how to send emails with Rails but can't seem to get it to work within the context of my current application.
I had an existing emailer.rb with a couple of methods that were identical apart from the parameters they accepted were named differently so I copied their format:
def quotation_notification(q)
#recipients = q.recipient_email
#from = q.partner_name + "<#{q.partner_email}>"
#subject = "New Quotation from " + q.partner_name
#body[:q] = q
end
I then created a new view file in emailers named quotation_notification.rhtml which just contains text for the moment.
I am then calling the function from inside a different controller and sending hardcoded parameters for now:
q = QuotationEmail.new(:recipient_email => 'martin#domain.co.uk', :partner_name => 'Martin Carlin', :partner_email => 'martin#domain.co.uk')
# send email
Emailer.deliver_quotation_notification(q)
Then finally, I created a new model for QuotationEmail
class QuotationEmail
def initialize(recipient_email, partner_name, partner_email)
#recipient_email = recipient_email
#partner_name = partner_name
#partner_name = partner_email
end
end
The error I get is ArgumentError (wrong number of arguments (1 for 3))
Eventually I'll be sending more parameters and hopefully attaching a pdf aswell but just trying to figure out why this isn't working first.
You are getting this error because while initialising QuotationEmail object though you think you're passing 3 params you're essentially passing only one parameter which is a hash. And initialize is expecting 3. See example below
class A
def initialize(a,b=1,c=2)
puts a
puts b
puts c
end
end
a = A.new(:recipient_email => 'martin#domain.co.uk', :partner_name => 'Martin Carlin', :partner_email => 'martin#domain.co.uk')
#=> {:recipient_email=>"martin#domain.co.uk", :partner_name=>"Martin Carlin", :partner_email=>"martin#domain.co.uk"}
#=> 1
#=> 2
If you're trying to use named parameters instead you'd need to redefine your initialize as
def initialize(recipient_email:a,partner_name:b,partner_email:c)
and invoke it as below -
a = A.new(recipient_email:'martin#domain.co.uk', partner_name:'Martin Carlin', partner_email:'martin#domain.co.uk')

rails increment on no error

I have a rails code that sends emails. Following is in my controller:
def create
#users = Users.find(:all)
#sub = params[:sub]
#body = params[:body]
#index = 0
#users.each {|i| index++; Notifier.deliver_notification(#users.email_address, #sub, #body, #users.unsubscribe_link);}
flash[:notice] = "Mail was sent to " + #index + " people"
end
I have the following in my Model
class Notifier < ActionMailer::Base
def notification(email, sub, content, link)
recipients email
from "my_email#example.com"
subject sub
body :content => recipient, :link => link
end
end
This all works fine. My Question is:
For example if there is an error in sending mail to one of the pople, even then my flash message will say. Mail was sent to X people
What can I do to ensure that #index gets incremented ONLY when mail is successfully sent?
The deliver_notification method should always return a TMail object regardless of success or failure. There is a raise_delivery_errors setting which will allow the mailer to raise exceptions if there's trouble, but you'll have to rescue these in your block and only increment on success.
Due to the way mail is delivered by ActionMailer, it's often the case you won't know if the message is successful or not. Email is usually queued and delivered at a point in time well beyond your method call, and most errors occur at this point due to any number of difficulties in delivery. It's only wildly malformed email addresses that will be rejected up front, or if the mail delivery mechanism is non-functional.
Edit: Added Exception Tracking
count = 0
#users.each do |user|
begin
Notifier.deliver_notification(
user.email_address,
#sub,
#body,
user.unsubscribe_link
)
count += 1
rescue => e
# Something went wrong, should probably store these and examine them, or
# at the very least use Rails.logger
end
end
flash[:notice] = "Mail was sent to #{count} people"
Your example used index++ which is not supported by Ruby. What you probably want is index += 1. You were also using the #users array directly instead of the individual elements.
You could ask ActionMailer to throw exceptions for you, and then only count those deliveries that don't result in an exception.
ActionMailer::Base.raise_delivery_errors = true
#users.each do |i|
begin
Notifier.deliver_notification(#users.email_address, #sub, #body, #users.unsubscribe_link)
index++
rescue Exception => e
# Do whatever you want with the failed deliveries here
end
end

Resources