send email to multiple recipients using net/smtp - ruby

I have this code:
require "net/smtp"
MAIL_SERVER = "xxx.ad.xxx.net"
def lib_sending_report(email_hash)
# define message body
message = <<"MESSAGE_END"
From: <#{email_hash[:sender]}>
To: <#{email_hash[:recipients]}>
MIME-Version: 1.0
Content-type: text/html
Subject: #{email_hash[:subject]}
<p>Hi All,</p>
<p>We've just executed a round of load test.</p>
<p>Regards</p>
MESSAGE_END
Net::SMTP.start(MAIL_SERVER) do |smtp|
smtp.send_message message, email_hash[:sender], email_hash[:recipients]
end
end
test = ""
lib_sending_report( {:sender => "abc#xxx.com",
:recipients => "abc#xxxx.com",
:subject => "Load.Test.Report.of.#{test}"} )
When I change :recipients => "abc#xxxx.com" to :recipients => "abc#xxxx.com;efg#xxx.com", it gives me this error:
501 5.5.4 Invalid Address (Net::SMTPSyntaxError)
I can successfully send email when :recipients => "abc#xxxx.com" just have one recipient.
Where am I wrong? It seems that the separator(semicolon) I used is wrong.
I tried to use comma instead of semicolon, but it didn't work

Net::SMTP's send_message takes an array of "To:" address strings.
Per the documentation:
to_addr is a String or Strings or Array of Strings, representing the destination mail address or addresses.
This example from the documentation shows how:
Net::SMTP.start('smtp.example.com') do |smtp|
smtp.send_message msgstr,
'from#example.com',
['dest#example.com', 'dest2#example.com']
end

Related

Ruby: I am trying to send an array in the email {body} but it does not send the array rather just text 'body' is send

Here is the code I tried
a = [1,2,3,4,5]
require 'net/smtp'
message = <<MESSAGE_END
From: Private Person <me#fromdomain.com>
To: A Test User <test#todomain.com>
Subject: Something
"#{a}" This is a test e-mail message.
MESSAGE_END
Net::SMTP.start('localhost') do |smtp|
smtp.send_message message, 'me#fromdomain.com',
'test#todomain.com'
end
I have figured a way around this
message =%Q(
Subject: Test suite result
#{a}
)
smtp = Net::SMTP.new 'smtp.gmail.com', 587
smtp.enable_starttls
smtp.start('smtp.gmail.com', 'from#mail.com', 'password', :plain) do |smtp|
smtp.send_message message, 'from#mail.com',
'to#mail.com'
end
But if I use above approach I am only able to send the body and cannot send subject and the to address.
Heredocs can accept variables like a normal string, using the #{var} syntax:
message = <<MESSAGE_END
From: Private Person <me#fromdomain.com>
To: A Test User <test#todomain.com>
Subject: #{a}
This is a test e-mail message.
MESSAGE_END
Source: https://stackoverflow.com/a/3332901

Mandrill - No message exists with id

I'm having an issue using the mandrill API for ruby and i'm not sure if it's a lack of ruby/api understanding on my part of if there's an issue with the mandrill api.
I have this method which sends an email with mandrill, and then I make another api call using the id returned from mandrill.messages.send to make another call to mandrill to get the email header message-id so i can store that in a db table.
Why am I getting the error Mandrill::UnknownMessageError (No message exists with the id '64fba1cce24942dea1ada4f905fd7871'): when the id clearly exists as seen in the comments for the logging events?
# Sends an email to all users for the account_id on the issue
def send_email
require 'mandrill'
...
mandrill = Mandrill::API.new Mandrill::API_KEY
# Email contents
message = {
:subject => self.name,
:from_name => self.account.subdomain,
:text => self.description,
:to => [{
:email => user.email,
:name => user.name
}],
:text => self.description,
:from_email => "noreply#myapp.com",
:headers => {
'reply-to' => 'update#myapp.com'
}
}
results = mandrill.messages.send message # Send email through mandrill
# Loop through results of sent email
results.each do |result|
logger.debug "result id = #{result['_id']}" # LOGS result id = 64fba1cce24942dea1ada4f905fd7871
logger.debug "result = #{result}" # LOGS result = {"email"=>"tomcaflisch#gmail.com", "status"=>"sent", "_id"=>"64fba1cce24942dea1ada4f905fd7871", "reject_reason"=>nil}
id = result['_id'] # Mandrill's internal id from api call results that sent the email
# CAUSES Mandrill::UnknownMessageError (No message exists with the id '64fba1cce24942dea1ada4f905fd7871'):
info = mandrill.messages.content id # Get info for sent email with a specific mandrill id
end
end
I think you just have to give it a little bit of time.
I am facing the same error on messages.info(id).
However, search('*') is finding all messages sent but not providing correct status information.
I think the following snippet of gem code is getting 500 status (instead of 200) when messages.info(id) is called:
def call(url, params={})
params[:key] = #apikey
params = JSON.generate(params)
r = #session.post(:path => "#{#path}#{url}.json", :headers => {'Content-Type' => 'application/json'}, :body => params)
cast_error(r.body) if r.status != 200
return JSON.parse(r.body)
end
Also, gem code is hosted on bitbucket instead of more common github. Not sure how to raise an issue there for support.
Sorry can't be of much help but thought I should share my experience also to get more visibility for the problem.

Ruby and sending emails with Net::SMTP: How to specify email subject?

I have a ruby app and I am sending emails with this format found in the documentation http://ruby-doc.org/stdlib-2.0/libdoc/net/smtp/rdoc/Net/SMTP.html :
Net::SMTP.start('your.smtp.server', 25) do |smtp|
smtp.send_message msgstr, 'from#address', 'to#address'
end
This is my code:
def send_notification(exception)
msgstr = <<-END_OF_MESSAGE
From: Exchange Errors <exchangeerrors#5112.mysite.com>
To: Edmund Mai <emai#mysite.com>
Subject: test message
Date: Sat, 23 Jun 2001 16:26:43 +0900
Message-Id: <unique.message.id.string#mysite.com>
This is a test message.
END_OF_MESSAGE
Net::SMTP.start('localhost', 25) do |smtp|
smtp.send_message(msgstr, "exchangeerrors#5112.mysite.com", "emai#mysite.com")
end
end
However, the emails being sent have no subjects in them. The msgstr just becomes the body of the email. I don't see anywhere in the documentation on how to specify a mail subject. Does anyone know?
So I looked at the documentation and it looks like Net::SMTP doesn't support this. In the documentation it says this:
What is This Library NOT?¶ ↑
This library does NOT provide functions to compose internet mails. You must create them by yourself. If you want better mail support, try RubyMail or TMail. You can get both libraries from RAA. (www.ruby-lang.org/en/raa.html)
So I looked into the MailFactory gem (http://mailfactory.rubyforge.org/), which uses Net::SMTP actually:
require 'net/smtp'
require 'rubygems'
require 'mailfactory'
mail = MailFactory.new()
mail.to = "test#test.com"
mail.from = "sender#sender.com"
mail.subject = "Here are some files for you!"
mail.text = "This is what people with plain text mail readers will see"
mail.html = "A little something <b>special</b> for people with HTML readers"
mail.attach("/etc/fstab")
mail.attach("/some/other/file")
Net::SMTP.start('smtp1.testmailer.com', 25, 'mail.from.domain', fromaddress, password, :cram_md5) { |smtp|
mail.to = toaddress
smtp.send_message(mail.to_s(), fromaddress, toaddress)
}
and now it works!
I know this mostly useless now but, I tried sending email using Net::SMTP and was able to set the subject. maybe you could have tried
Subject: 'test message' instead of Subject: test message
I actually managed to send a mail with NET::SMTP with a subject, I think that the indentation is important (example taken from http://www.tutorialspoint.com/ruby/ruby_sending_email.htm) -
message = <<MESSAGE_END
From: Private Person <me#fromdomain.com>
To: A Test User <test#todomain.com>
Subject: SMTP e-mail test
This is a test e-mail message.
MESSAGE_END
Net::SMTP.start('localhost') do |smtp|
smtp.send_message message, 'me#fromdomain.com',
'test#todomain.com'
end
The Subject will be correct. If you print the variable "message" you'll get this output-
"From: Private Person <me#fromdomain.com>\nTo: A Test User <test#todomain.com>\nSubject: SMTP e-mail test\n\nThis is a test e-mail message.\n"
While this code, with spaces in front of "Subject" -
message = <<MESSAGE_END
From: Private Person <me#fromdomain.com>
To: A Test User <test#todomain.com>
Subject: SMTP e-mail test
This is a test e-mail message.
MESSAGE_END
Net::SMTP.start('localhost') do |smtp|
smtp.send_message message, 'me#fromdomain.com',
'test#todomain.com'
end
will print -
"From: Private Person <me#fromdomain.com>\nTo: A Test User <test#todomain.com>\n Subject: SMTP e-mail test\n\nThis is a test e-mail message.\n"
And then the subject won't work.

UndefinedConversionError trying to parse Arabic from email body

using mail for ruby I am getting this message:
mail.rb:22:in `encode': "\xC7" from ASCII-8BIT to UTF-8 (Encoding::UndefinedConversionError)
from mail.rb:22:in `<main>'
If I remove encode I get a message ruby
/var/lib/gems/1.9.1/gems/bson-1.7.0/lib/bson/bson_ruby.rb:63:in `rescue in to_utf8_binary': String not valid utf-8: "<div dir=\"ltr\"><div class=\"gmail_quote\">l<br><br><br><div dir=\"ltr\"><div class=\"gmail_quote\"><br><br><br><div dir=\"ltr\"><div class=\"gmail_quote\"><br><br><br><div dir=\"ltr\"><div dir=\"rtl\">\xC7\xE1\xE4\xD5 \xC8\xC7\xE1\xE1\xDB\xC9 \xC7\xE1\xDA\xD1\xC8\xED\xC9</div></div>\r\n</div><br></div>\r\n</div><br></div>\r\n</div><br></div>" (BSON::InvalidStringEncoding)
This is my code:
require 'mail'
require 'mongo'
connection = Mongo::Connection.new
db = connection.db("DB")
db = Mongo::Connection.new.db("DB")
newsCollection = db["news"]
Mail.defaults do
retriever_method :pop3, :address => "pop.gmail.com",
:port => 995,
:user_name => 'my_username',
:password => '*****',
:enable_ssl => true
end
emails = Mail.last
#Checks if email is multipart and decods accordingly. Put to extract UTF8 from body
plain_part = emails.multipart? ? (emails.text_part ? emails.text_part.body.decoded : nil) : emails.body.decoded
html_part = emails.html_part ? emails.html_part.body.decoded : nil
mongoMessage = {"date" => emails.date.to_s , "subject" => emails.subject , "body" => plain_part.encode('UTF-8') }
msgID = newsCollection.insert(mongoMessage) #add the document to the database and returns it's ID
puts msgID
For English and Hebrew it works perfectly but it seems gmail is sending arabic with different encoding. Replacing UTF-8 with ASCII-8BIT gives a similar error.
I get the same result when using plain_part for plain email messages. I am handling emails from one specific source so I can put html_part with confidence it's not causing the error.
To make it extra weird Subject in Arabic is rendered perfectly.
What encoding should I use?
If you use encode without options, it will raise this error, if you're string pretends to be an encoding but contains characters from another encoding.
try it in this way:
plain_part.encode('UTF-8', {:invalid => :replace, :undef => :replace, :replace => '?'})
this replaces invalid and undefined chars for the given encoding with an "?"(more info). If this is not sufficent for your needs, you need to find a way to check if your plain_part string is valid.
For example you can use valid_encoding?(more info) for this.
I recently stumbled across a similar problem, where I couldn't be sure what encoding it really is, so I wrote this (maybe a little humble) method. May it helps you, to find a way to fix your problem.
def self.encode!(str)
return nil if str.nil?
known_encodings = %w(
UTF-8
ISO-8859-1
)
begin
str.encode(Encoding.find('UTF-8'))
rescue Encoding::UndefinedConversionError
fixed_str = ""
known_encodings.each do |encoding|
fixed_str = str
if fixed_str.force_encoding(encoding).valid_encoding?
return fixed_str.encode(Encoding.find('UTF-8'))
end
end
return str.encode(Encoding.find('UTF-8'), {:invalid => :replace, :undef => :replace, :replace => '?'})
end
end
I found a work around.
Since only specific emails will be sent to this account to just to use on this application I have full control over formatting. For some reason mail decodes text/plain attachment perfectly
so:
emails.attachments.each do | attachment |
if (attachment.content_type.start_with?('text/plain'))
# extracting txt file
begin
body = attachment.body.decoded
rescue Exception => e
puts "Unable to save data for #{filename} because #{e.message}"
end
end
end
mongoMessage = {"date" => emails.date.to_s , "subject" => emails.subject , "body" => body }

Attempt at authenticated SMTP in Ruby

I've looked at all the SMTP ruby-docs and can't figure out where I'm going wrong:
def send(username, password, data, toAddress, fromAddress)
smtp = Net::SMTP.new('my.smtp.host', 25)
smtp.start('thisisunimportant', username, password, "plain") do |sender|
sender.send_message(data, fromAddress, toAddress)
end
end
send(user, pass, rcpt, "Hey!")
Gives an unexpected kind of error:
/usr/lib/ruby/1.9.1/net/smtp.rb:725:in authenticate': wrong number of arguments (3 for 4) (ArgumentError)
from /usr/lib/ruby/1.9.1/net/smtp.rb:566:indo_start'
from /usr/lib/ruby/1.9.1/net/smtp.rb:531:in start'
from gmx_pop.rb:24:insend'
from gmx_pop.rb:30:in `'
I've tried kicking my computer a couple times but the problem persists.
Here's a description of the Net::SMTP#start call:
http://ruby-doc.org/stdlib-1.9.1/libdoc/net/smtp/rdoc/Net/SMTP.html#method-i-start
the page mentions that you can just do SMTP.start to do everything at once.
Look like you are missing the port parameter. Try port 587 for secure authentication, if that doesn't work, port 25. (check the tutorial mentioned below)
Your call should look like this:
message_body = <<END_OF_EMAIL
From: Your Name <your.name#gmail.com>
To: Other Email <other.email#somewhere.com>
Subject: text message
This is a test message.
END_OF_EMAIL
server = 'smtp.gmail.com'
mail_from_domain = 'gmail.com'
port = 587 # or 25 - double check with your provider
username = 'your.name#gmail.com'
password = 'your_password'
smtp = Net::SMTP.new(server, port)
smtp.enable_starttls_auto
smtp.start(server,username,password, :plain)
smtp.send_message(message_body, fromAddress, toAddress) # see note below!
Important:
Please note that you need to add To: , From: , Subject: headers to your message_body!
the Message-Id: and Date: headers will be added by your SMTP server
Check also:
Tutorial : http://www.java-samples.com/showtutorial.php?tutorialid=1121
the source code for Net::SMTP under ~/.rvm/src/ruby-1.9.1*/lib/net/smtp.rb
(Ruby) Getting Net::SMTP working with Gmail...?
Another way to send emails from Ruby:
You can use the ActionMailer gem from Rails to send emails from Ruby (without Rails).
At first this seems like overkill, but it makes it much easier, because you don't have to format the message body with To: , From: , Subject: , Date: , Message-Id: Headers.
# usage:
# include Email
#
# TEXT EMAIL :
# send_text_email( 'sender#somewhere.com', 'sender#somewhere.com,receiver#other.com', 'test subject', 'some body text' )
# HTML EMAIL :
# send_html_email( 'sender#somewhere.com', 'sender#somewhere.com,receiver#other.com', 'test subject', '<html><body><h1>some title</h1>some body text</body></html>' )
require 'action_mailer'
# ActionMailer::Base.sendmail_settings = {
# :address => "Localhost",
# :port => 25,
# :domain => "yourdomain.com"
# }
ActionMailer::Base.smtp_settings = { # if you're using GMail
:address => 'smtp.gmail.com',
:port => 587,
:domain => 'gmail.com',
:user_name => "your-username#gmail.com"
:password => "your-password"
:authentication => "plain",
:enable_starttls_auto => true
}
class SimpleMailer < ActionMailer::Base
def simple_email(the_sender, the_recepients, the_subject, the_body , contenttype = nil)
from the_sender
recipients the_recepients
subject the_subject
content_type contenttype == 'html' ? 'text/html' : 'text/plain'
body the_body
end
end
# see http://guides.rails.info/action_mailer_basics.html
# for explanation of dynamic ActionMailer deliver_* methods.. paragraph 2.2
module Email
# call this with a message body formatted as plain text
#
def send_text_email( sender, recepients, subject, body)
SimpleMailer.deliver_simple_email( sender , recepients , subject , body)
end
# call this with an HTML formatted message body
#
def send_html_email( sender, recepients, subject, body)
SimpleMailer.deliver_simple_email( sender , recepients , subject , body, 'html')
end
endsubject , body, 'html')
end
end
e.g. the code above works if you want to use Gmail's SMTP server to send email via your Gmail account.. Other SMTP servers may need other values for :port, :authentication and :enable_starttls_auto depending on the SMTP server setup
Try this code
Net::SMTP.smtp.start('my.smtp.host', 25, 'mail.from.domain', username, password, :plain) do |smtp|
smtp.send_message data, fromAddress, toAddress
end

Resources