Sending multipart mails and attachments - ruby

I am trying to send an E-Mail using the gem 'mail' with Ruby 1.9.3. It contains an text/html and an text/plain part which should be embedded as alternative parts as well an attachment.
This is my current code:
require 'mail'
mail = Mail.new
mail.delivery_method :sendmail
mail.sender = "me#example.com"
mail.to = "someguy#example.com"
mail.subject = "Multipart Test"
mail.content_type = "multipart/mixed"
html_part = Mail::Part.new do
content_type 'text/html; charset=UTF-8'
body "<h1>HTML</h1>"
end
text_part = Mail::Part.new do
body "TEXT"
end
mail.part :content_type => "multipart/alternative" do |p|
p.html_part = html_part
p.text_part = text_part
end
mail.add_file :filename => "file.txt", :content => "FILE"
mail.deliver!
It results in an mail with working alternative parts but no attachment. I am using thunderbird 10.0.12 for testing.
I already posted this on github, but unfortunately the posts don't make me smarter. https://github.com/mikel/mail/issues/118#issuecomment-12276876. Maybe somebody is able to understand the last post a bit better than me ;)
Is somebody able to get this example working?
Thanks,
krissi

I managed to fix it like so:
html_part = Mail::Part.new do
content_type 'text/html; charset=UTF-8'
body html
end
text_part = Mail::Part.new do
body text
end
mail.part :content_type => "multipart/alternative" do |p|
p.html_part = html_part
p.text_part = text_part
end
mail.attachments['some.xml'] = {content: Base64.encode64(theXML), transfer_encoding: :base64}
mail.attachments['some.pdf'] = thePDF
mail.content_type = mail.content_type.gsub('alternative', 'mixed')
mail.charset= 'UTF-8'
mail.content_transfer_encoding = 'quoted-printable'
Not intuitive at all, but reading the Pony source code kinda helped, as well as comparing a working .eml to whatever this gem was generating.

This seems to be a bug regarding the content type of the attachment. See https://github.com/mikel/mail/issues/522

Related

How to perform the following curl request using the ruby Faraday gem?

This is the curl request I'd like to perform:
curl --request GET --url 'https://us8.api.mailchimp.com/3.0/' --user 'anystring:<apikey>'
Running this curl command from the command line, I get a bunch of JSON, which is what I want.
I'm trying to perform this same request using Faraday. This is what I've tried:
conn = Faraday.new "https://us8.api.mailchimp.com/3.0/" do |faraday|
faraday.adapter Faraday.default_adapter
end
conn.basic_auth('apikey', <apikey>)
response = conn.get
puts response.body # => "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>301 Moved Permanently</title>\n</head>...
How do I get JSON instead of the html I'm seeing in response.body?
This ended up working for me:
conn = Faraday.new('https://us8.api.mailchimp.com/3.0/') do |c|
c.use FaradayMiddleware::ParseJson, content_type: "application/json"
c.use Faraday::Adapter::NetHttp
end
conn.basic_auth('apikey', <api_key>)
response = conn.get('campaigns')
puts response # => json blob
A much more concise option is to manually encode your credentials into Base64 and set the Authorization header manually. This saves a few lines of code and keeps it in a similar format to regular Faraday requests (i.e. Faraday.post <URL>, <BODY>, <HEADERS>).
i.e.
encoded_credentials = Base64.encode64('apikey:api_secret').chomp
Faraday.post 'http://myhost.local/my_url', {}, authorization: "Basic #{encoded_credentials}"
This is the farday code for curl operations using ruby gem.
def contacts
response = JSON.parse(params)
#conn = Faraday.new('https://domain.example.com/api/v2/') do |farday|
farday.use FaradayMiddleware::ParseJson, content_type: "application/json"
farday.use Faraday::Adapter::NetHttp
end
#conn.basic_auth('apikey', <your_api_key>)
response = #conn.get('contacts')
puts response
render :json => {"success" => true}
end

Twilio - Save SMS body, sid and sender in Ruby

I have followed the guide here to set up a sinatra app that successfully receives and responds to a text sent to my Twilio account.
require 'sinatra'
require 'twilio-ruby'
post '/receive_sms' do
content_type 'text/xml'
response = Twilio::TwiML::Response.new do |r|
r.Message 'Message recieved'
end
response.to_xml
end
How can I retrieve the SMS body, sender, and SID of the message and store them as a variable? Ex: body = "Test message"
I have tried adding response.text to return the xml response and possibly parse the output but did not have any luck with this.
Twilio developer evangelist here.
The message parameters are sent as form encoded parameters, which luckily Sinatra already reads for you. You can get the body, sender and SID like so:
require 'sinatra'
require 'twilio-ruby'
post '/receive_sms' do
body = params["Body"]
sid = params["MessageSid"]
sender = params["From"]
content_type 'text/xml'
response = Twilio::TwiML::Response.new do |r|
r.Message 'Message recieved'
end
response.to_xml
end
You can see all the parameters available in Twilio's request in the documentation.

send mail with attachment ruby

I want send mail with an attachment file. I need have then format body text in html, when configure the format, the file attachment sent bad in the mail.
My code using actionMailer:
#require 'mail'
class MyMail < ActionMailer::Base
default :from => 'cristian.gonzalez#powersystem.com.ar'
def send_mail(user,pdffile_name,pdffile_name_second,pdffile_name_thir,htmlfile_name)
#sendgrid_unique_args :key1 => user.id
email_with_name = "#{user.send_user} <#{user.mail_address}>"
#Adjuntar el archivo 1
unless pdffile_name.nil?
filename = user.first_attachment.partition("/")[2]
attachments[filename] = File.open(pdffile_name, 'rb', &:read)
end
mail :to => 'cdgonzalez82#gmail.com',
:subject = user.mail_subject,
:content_type = 'text/html; charset=UTF-8',
:email.body = user.mail_body
end
end
Any help please???

Specifying Content Type in rspec

I'm trying to build an rspec test that sends JSON (or XML) via POST. However, I can't seem to actually get it working:
json = {.... data ....}.to_json
post '/model1.json',json,{'CONTENT_TYPE'=>'application/json'}
and this
json = {.... data ....}.to_json
post '/model1.json',json,{'Content-Type'=>'application/json'}
any ideas? THANKS!
In Rails 3, you can skip the header and #request.env stuff and just add a format parameter to your post call, e.g.:
post :create, format: :json, param: 'Value of Param'
There's a way to do this described in this thread -- it's a hack, but it seems to work:
#request.env["HTTP_ACCEPT"] = "application/json"
json = { ... data ... }.to_json
post :create, :some_param => json
A lot of frustration and variations and that's what worked for me.
Rails 3.2.12 Rspec 2.10
#request.env["HTTP_ACCEPT"] = "application/json"
#request.env["CONTENT_TYPE"] = "application/json"
put :update, :id => 1, "email" => "bing#test.com"
First of all, you don't want to test the built-in conversion of json to hash. Same applies to xml.
You test controller with data as hashes, not bothering wether it's json, xml or from a html form.
But if you would like to do that as an exercise, this is a standalone ruby script to do play with :)
require 'json'
url = URI.parse('http://localhost:3030/mymodels.json')
request = Net::HTTP::Post.new(url.path)
request.content_type="application/json"
request.basic_auth('username', 'password') #if used, else comment out
hash = {:mymodel => {:name => "Test Name 1", :description => "some data for testing description"}}
request.body = hash.to_json
response = Net::HTTP.start(url.host, url.port) {|http| http.request(request)}
puts response
to switch to xml, use content_type="text/xml" and
request.body = "<?xml version='1.0' encoding='UTF-8'?><somedata><name>Test Name 1</name><description>Some data for testing</description></somedata>"
A slightly more elegant test is to use the header helper:
header "HTTP_ACCEPT", "application/json"
json = {.... data ....}.to_json
post '/model1.json', json
Now this does exactly the same thing as setting #env; it's just a bit prettier.
The best way that I have found to test these things is with request tests. Request tests go through the full param parsing and routing stages of Rails. So I can write a test like this:
request_params = {:id => 1, :some_attribute => "some value"}
headers = {'Accept' => 'application/json', 'Content-Type' => 'application/json'}
put "/url/path", request_params.to_json, headers
expect(response).to be_success
I think that you can specify the headers with headers param:
post '/model1.json', headers: {'Content-type': 'application/json'}
Following the Rspec documentation of how provide JSON data.
#request.env["CONTENT_TYPE"] = "application/json"
OR pass in request
"CONTENT_TYPE" => "application/json"

Ruby mechanize post with header

I have page with js that post data via XMLHttpRequest and server side script check for this header, how to send this header?
agent = WWW::Mechanize.new { |a|
a.user_agent_alias = 'Mac Safari'
a.log = Logger.new('./site.log')
}
agent.post('http://site.com/board.php',
{
'act' => '_get_page',
"gid" => 1,
'order' => 0,
'page' => 2
}
) do |page|
p page
end
I found this post with a web search (two months later, I know) and just wanted to share another solution.
You can add custom headers without monkey patching Mechanize using a pre-connect hook:
agent = WWW::Mechanize.new
agent.pre_connect_hooks << lambda { |p|
p[:request]['X-Requested-With'] = 'XMLHttpRequest'
}
ajax_headers = { 'X-Requested-With' => 'XMLHttpRequest', 'Content-Type' => 'application/json; charset=utf-8', 'Accept' => 'application/json, text/javascript, */*'}
params = {'emailAddress' => 'me#my.com'}.to_json
response = agent.post( 'http://example.com/login', params, ajax_headers)
The above code works for me (Mechanize 1.0) as a way to make the server think the request is coming via AJAX, but as stated in other answers it depends what the server is looking for, it will be different for different frameworks/js library combos.
The best thing to do is use Firefox HTTPLiveHeaders plugin or HTTPScoop and look at the request headers sent by the browser and just try and replicate that.
Seems like earlier that lambda had one argument, but now it has two:
agent = Mechanize.new do |agent|
agent.pre_connect_hooks << lambda do |agent, request|
request["Accept-Language"] = "ru"
end
end
Take a look at the documentation.
You need to either monkey-patch or derive your own class from WWW::Mechanize to override the post method so that custom headers are passed through to the private method post_form.
For example,
class WWW::Mechanize
def post(url, query= {}, headers = {})
node = {}
# Create a fake form
class << node
def search(*args); []; end
end
node['method'] = 'POST'
node['enctype'] = 'application/x-www-form-urlencoded'
form = Form.new(node)
query.each { |k,v|
if v.is_a?(IO)
form.enctype = 'multipart/form-data'
ul = Form::FileUpload.new(k.to_s,::File.basename(v.path))
ul.file_data = v.read
form.file_uploads << ul
else
form.fields << Form::Field.new(k.to_s,v)
end
}
post_form(url, form, headers)
end
end
agent = WWW::Mechanize.new
agent.post(URL,POSTDATA,{'custom-header' => 'custom'}) do |page|
p page
end

Resources