This is in a Rails 4 app. I'm trying to send emails with attachments for the first time. It's a really basic test email:
class Emailer < ActionMailer::Base
def test_attachments
attachments['file.pdf'] = File.read('/path/to/file.pdf')
mail(to: me#me.com, from: sender#me.com, body: "")
end
end
Emailer.test_attachments.deliver
This results in an error. IndexError string not matched Looking at the API docks, it looks like attachments is an instance method, so my next try uses that:
class Emailer < ActionMailer::Base
def test_attachments
mail(to: me#me.com, from: sender#me.com, body: "")
mail.attachments['file.pdf'] = File.read('/path/to/file.pdf')
end
end
Emailer.test_attachments.deliver
This results in the attachment contents sent in the body of the email. Here's the mail instance:
#<Mail::Message:70259446276180, Multipart: false, Headers: <Date: Tue, 08 Jul 2014 12:09:14 -0400>, <From: sender#me.com>, <To: ["me#me.com"]>, <Message-ID: <53bc17c1e3194_122583fe68982dbc473cc#Johns-iMac-3.local.mail>>, <Subject: >, <Mime-Version: 1.0>, <Content-Type: text/html>, <Content-Transfer-Encoding: 7bit>>
Related
In a script which sends emails through Net::SMTP, I've to figure out how to properly encode the email body in order to support accentuated characters. I've separated the email into 3 parts: headers, body and attachment, as from this tutorial https://www.tutorialspoint.com/ruby/ruby_sending_email.htm
Fixing this issue for the Subject header field wasn't a big deal:
require 'base64'
MARKER = 'FOOBAR'
def self.headers
<<~EOF
From: someemail#domain.tld
To: anotheremail#domaim.tld
# Base64 encoded UTF-8
Subject: =?UTF-8?B?#{Base64.strict_encode64('Accentuated characters supportés')}?=
Date: #{Time.now.to_s}
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=#{MARKER}
--#{MARKER}
EOF
end
I was tempted to reproduce the same logic for the email body, without any success. I've try several headers, such as Language, Content-Language, Content-Tranfer-Encoding, again, without any success. Using Ruby's .encode!('utf-8') was also ineffective.
The only working solution I can think of would be to send HTML encoded characters: using é instead of é inside a HTML block. Though, I'd like to avoid this solution as I've to improve my comprehension of encoding issues.
Does anyone has a suggestion about this issue ?
Here's my code so far, if it can help anyone:
module Reports
module SMTP
MARKER = 'FOOBAR'
def self.send_report(file_path)
file_content = File.binread(file_path)
encoded_content = [file_content].pack('m') # Base64
mail_content = headers + body + attachment(file_path, encoded_content)
begin
Net::SMTP.start('my.smtp.srv', 25, 'HELO_fqdn', 'username', 'p455w0rD', :plain) do |smtp|
smtp.send_message(mail_content, 'from#domain.tld', ['to1#domain.tld', 'to2#domain.tld'])
end
rescue => e
puts e.inspect, e.backtrace
end
end
def self.headers
# see above
end
def self.body
<<~EOF
Content-Type: text/html
Content-Transfer-Encoding:utf8
Here's a franglish text with some characters accentués
--#{MARKER}
EOF
end
def self.attachment(file_path, encoded_content)
<<~EOF
Content-Type: multipart/mixed; name = #{file_path}
Content-Transfer-Encoding:base64
Content-Disposition: attachment; filename = #{file_path}
#{encoded_content}
--#{MARKER}--
EOF
end
end
end
Note: these emails are correctly decoded by ProtonMail webclients, but our company's webclient (OBM) doesn't display accentuated character nor attachment properly.
Adding ;charset="utf-8" to the Content-Type header from the body part fixed my problem.
Content-Type: text/html;charset="utf-8"
I've managed to send emails via Google API thanks to the google-api-client gem:
def send_message(from:, to:, subject:, body:)
message = RMail::Message.new
message.header['From'] = from
message.header['To'] = to
message.header['Subject'] = subject
message.body = body
#service.send_user_message(
'me',
upload_source: StringIO.new(message.to_s),
content_type: 'message/rfc822'
)
end
Now I'm trying to attach files to the emails, but I couldn't find examples on how to do it. The example included in the gem's repository doesn't explain the case. I've started doing reverse engineering, but after almost the whole day making attempts I've started doing crazy things.
My last attempt was the following:
upload = Google::Apis::Core::UploadIO.new('/path/to/image.png', 'image/png', 'image.png')
file_part = Google::Apis::Core::FilePart.new(nil, upload)
message_object = Google::Apis::GmailV1::Message.new(payload: file_part, raw: 'this is a test body')
service.send_user_message('me', message_object, content_type: 'message/rfc822')
The Email was bounced.
What's the proper way to attach files?
Turns out it was easier than I expected. Here is an example:
class Client
def initialize(service)
#service = service
end
def send_message(from:, to:, subject:, body:)
message = RMail::Message.new
message.header.set('From', from)
message.header.set('To', to)
message.header.set('Subject', subject)
message.body = [text_part(body), file_part]
#service.send_user_message(
'me',
upload_source: StringIO.new(message.to_s),
content_type: 'message/rfc822'
)
end
private
def text_part(body)
part = RMail::Message.new
part.body = body
part
end
def file_part
part = RMail::Message.new
part.header.set('Content-Disposition', 'attachment', 'filename' => File.basename('/path/to/image.png'))
part.body = File.read('/path/to/image.png')
part
end
end
I'll wait for further responses, maybe there's something I'm not taking into account.
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
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
I've set up ActionMailer 3.x for use outside of Rails, but the emails don't have a body. Can anyone help?
# ./app.rb
require 'action_mailer'
ActionMailer::Base.delivery_method = :file
ActionMailer::Base.file_settings[:location] = './tmp/mails'
ActionMailer::Base.view_paths = './views'
class Mailer < ActionMailer::Base
def instructions(email_address)
mail(:to => email_address, :subject => 'hello')
end
end
Mailer.instructions('test#email.com').deliver
Then I have two files for my views, one for plain text
# ./views/mailer/instructions.text.erb
These are some instructions
And one for html (using HAML - I know there are some potential issues with this, any advice here would be appreciated too!)
# ./views/mailer/instructions.html.haml
%html
%body
%h1 These are some HTML instructions
But if I check my newly created ./tmp/mails/test#email.com I only have the following, and no body text:
Date: Wed, 07 Sep 2011 18:38:09 +0530
From: my#address.com
To: test#email.com
Message-ID: <4e676ab8e2bc5_274560aab8567d0#mycomputer.mail>
Subject: hello
Mime-Version: 1.0
Content-Type: text/plain;
charset=UTF-8
Content-Transfer-Encoding: 7bit
Any ideas what's going on here? Thanks in advance
After migration from Rails 2.x -> 3.x I had the same problem (a bit different setup though). My html emails had no body. I moved my mailer class from models folder into mailers folder and changed my view file names:
file_name.text.html.erb
=>
file_name.html.erb
I hope this helps.