Send Mail with attachment in Rails 3.0 using ActionMailer::Base in one or two lines - ruby-on-rails-3

This is my first quesiton, but what I'm trying to do is send mail with an attachment in rails console, using one or two lines. I dont want to instantiate a class like ..
class Mailer < ActionMailer::Base
...
end
I want to try it this way:
m=ActionMailer::Base.mail(:to => "harry#example.com", :from => "test#example.com", :subject=>"test from zip", :content_type=>"multipart/mixed")
m.attachments['file.zip']={:mime_type => "application/zip", :data=>File.read("#{Rails.root}/tmp/test.zip")}
m.deliver
This will send an email, but the attachment called noname, which can't be unzipped. It seems that its not parsing the data correctly for the attachment. If I look at the raw email the attachment contents looks something like this:
--
Date: Tue, 06 Mar 2012 06:59:42 -0800
Mime-Version: 1.0
Content-Type: application/zip;
charset=UTF-8
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename=file.zip
Content-ID: <4f56264f16e82_498a46e93467093#ip-10-125-15-127.mail>
UEsDBBQAAAAIAE9iZUBSMYOwkKgZANRakgAQABUAbG9hbl9kZXRhaWxzLmNz
dlVUCQADlh9VT0QfVU9VeAQA6APoA8xdW3PiuLZ+37+Ch6ldZ1dZGUvyNW/c
EwKBQLiENze4gytgZ9tmMplff5YMlgQWmV1tk5qufiAkwV8trcu3bko/8sLa
m/+p9dmLJPXSfaI1oyR4Df21Non28crPvt+MfS/117Uo5C+9VKu/v8fRH4e3
O0HobWte9g68gHdaQfJjHyeHb4/9/+79JPu9XbQPU22y2kTRVuv74dqPa7G/
...
1) is it even possible to send an email with an attachment like this, with out using something like the pony gem

An estimation to why it isn't working
According to SO post Invalid filename in email (ActionMailer) it seems to be ActionMailer wanting to automagically glean information from files, something which is unavailable from the console.
I noted that the following, albeit messy, works (sufficiently for my purposes) from the console:
File.open("magical_elephant_potato.txt", 'w') {|f| f.write("Heyyyy youuu!") }
m=ActionMailer::Base.mail(:to => "rainbowpony#company.com", :from => "noreply#railsapp.com", :subject=>"Behold my MEP attache", :content_type=>"multipart/mixed")
m.attachments['magical_elephant_potato.txt']=File.read("magical_elephant_potato.txt")
m.deliver
FileUtils.rm('magical_elephant_potato.txt')
Given that writing and removing files via console works, perhaps the files required by ActionMailer can be written, utilised then deleted? We're heading into sticky work-around territory here though. A problem is that ActionMailer will look for the appropriate mailer view, but how and can we tell ActionMailer where to look for the mailer files? (As in, the filename)
As for the information not being encoded correctly, I think the problem is that its being wrapped in the 'noname' file with some header info. The data is likely intact, as with my example I get:
--
Date: Tue, 08 Jan 2013 11:08:57 +0000
Mime-Version: 1.0
Content-Type: text/plain;
charset=UTF-8;
filename=magical_elephant_potato.txt
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename=magical_elephant_potato.txt
Content-ID: <50bbfe4898ac_6d7febf6a312062#ws9.companydev.com.mail>
Heyyyy youuu!
----
:when I open 'noname' with a text editor.

Related

uploading large files in tornado using #stream_request_body

#stream_request_body
class StreamHandler(RequestHandler):
def post(self):
self.temp_file.close()
def prepare(self):
max_buffer_size = 4 * 1024**3 # 4GB
self.request.connection.set_max_body_size(max_buffer_size)
self.temp_file = open("test.txt","w")
def data_received(self, chunk):
self.temp_file.write(chunk)
With the above code I am able to upload file but in raw data form as shown below
-----------------------------6552719992117258671800152707
Content-Disposition: form-data; name="dest"
csv
-----------------------------6552719992117258671800152707
Content-Disposition: form-data; name="carrier"
bandwidth
-----------------------------6552719992117258671800152707
Content-Disposition: form-data; name="file1"; filename="test.csv"
Content-Type: text/csv
And the content of uploaded file follows here.
How do I get the request parameters parsed from the file and separate the data of the file uploaded?
Is there any other way to upload large files(around 2 GB) in tornado
This is the multipart protocol used by HTML forms. Tornado can currently only parse this if it sees all the data at once, not in a streaming upload. There's a third-party library that should be able to handle this: https://github.com/siddhantgoel/streaming-form-data. See this issue for more: https://github.com/tornadoweb/tornado/issues/1842
If you control the client, it may be simpler to use a plain HTTP PUT instead of the HTML multipart form protocol. This doesn't require any special handling on the server side

S/mime timestamp support

OK now I do have the timestamp from a TS provider.
How am I supposed to put it in a mime message so to comply with the standards?
As far as I know, no mailer supports timestamping, and this will not be a problem because I will be handling the mime message myself.
However I want to make it the standard way... any examples?
Thanks.
I think #Michael's own answer is just quite there with the following caveats:
An application/timestamp-replyis intended to transport a TimeStampResp which may or may not contain a TimeStampToken, and for the current purpose a TimeStampToken is always required to exist. See RFC 3161, "2.4.2. Response Format".
application/timestamp-reply content type is not currently defined as a security multipart protocol. See RFC 1847, "1. Introduction" and RFC 3161, "3.1. Time-Stamp Protocol Using E-mail".
Because of the previous I suggest the following sample structure:
MIME-Version: 1.0
Content-Type: multipart/signed; protocol="application/timestamp-signature"; micalg="sha256"; boundary="{79EAC9E2-BAF9-11CE-8C82-00AA004BA90B}"
--{79EAC9E2-BAF9-11CE-8C82-00AA004BA90B}
MIME-Version: 1.0
Content-Type: text/plain
Hello
--{79EAC9E2-BAF9-11CE-8C82-00AA004BA90B}
Content-Type: application/timestamp-signature; name="tst.bin"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="tst.bin"
MIINygYJKoZIhvcNAQcCoIINuzCCDbcCAQMxDzANBglghkgBZQMEAgEFADB5BgsqhkiG9w0BCRAB
BKBqBGgwZgIBAQYLYIZIAYb9bgEHFwQwMTANBglghkgBZQMEAgEFAAQg7fR3pD+6Lw0dlYtTjYke
...
vlwFfWaVsUq6VyE0Sw3mVxQGooR7/GH10QSP7bNQqHNWyk1kX+9FlrRY3BPjsvJ046+ol74/3QkB
WA7ZrAGzhwRBPQKfkCXysHwtDIj7iF1YXcXoeKQ1SWiGjhIHCpCXMJwNiapZQfYsnZQbI6L/xXMA
--{79EAC9E2-BAF9-11CE-8C82-00AA004BA90B}--
Where
tst.bin is a TimeStampToken.
application/timestamp-signature is an non-standard security multipart protocol.
Edit:
There seems to be a couple of standards that could fit here:
RFC 5544 - "Syntax for Binding Documents with Time-Stamps"
RFC 5955 - "The application/timestamped-data Media Type"
But I did not have the time to check them in detail.
I believe this is the appropriate format:
MIME-Version: 1.0
Content-Type: multipart/signed; protocol="application/timestamp-reply"; micalg="sha256"; boundary="{79EAC9E2-BAF9-11CE-8C82-00AA004BA90B}"
--{79EAC9E2-BAF9-11CE-8C82-00AA004BA90B}
MIME-Version: 1.0
Content-Type: text/plain
Hello
--{79EAC9E2-BAF9-11CE-8C82-00AA004BA90B}
Content-Type: application/timestamp-reply; name="smime.tsr"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="smime.tsr"
MIIIUgYJKoZIhvcNAQcCoIIIQzCCCD8CAQMxDzANBglghkgBZQMEAgEFADCCAQ4G
CyqGSIb3DQEJEAEEoIH+BIH7MIH4AgEBBgorBgEEAbIxAgEBMDEwDQYJYIZIAWUD
BAIBBQAEIO30d6Q/ui8NHZWLU42JHpvHqwcukBtDCZiWtieBErjfAhQJsQprheA+
j/8hfRdCJYqNwURr+BgPMjAxNjA3MjgxMTM4NDdaoIGMpIGJMIGGMQswCQYDVQQG
EwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxm
b3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEsMCoGA1UEAxMjQ09NT0RP
IFNIQS0yNTYgVGltZSBTdGFtcGluZyBTaWduZXKgggSgMIIEnDCCA4SgAwIBAgIQ
TrCHj8wkNTay2Mn3vzlVdzANBgkqhkiG9w0BAQsFADCBlTELMAkGA1UEBhMCVVMx
CzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMV
VGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0
cnVzdC5jb20xHTAbBgNVBAMTFFVUTi1VU0VSRmlyc3QtT2JqZWN0MB4XDTE1MTIz
MTAwMDAwMFoXDTE5MDcwOTE4NDAzNlowgYYxCzAJBgNVBAYTAkdCMRswGQYDVQQI
ExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoT
EUNPTU9ETyBDQSBMaW1pdGVkMSwwKgYDVQQDEyNDT01PRE8gU0hBLTI1NiBUaW1l
IFN0YW1waW5nIFNpZ25lcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AM68dLdwgE9e8z+Yqi7L1BIBIzVpCyK85v0JbCjkExKsu7ot5dXdIu5ztiz40qRx
50kleKslt5AQoJuLdybdQOpBo/2IzXKmiTtQVxx6JSQiAlFANWeKMWkN5TlzSTmb
lQGFUvIrFImaTgSkvECuOabdQALgOnX+PX1VlFvxTiR8yLhYGcrA2r5YE5rmHOfR
wTvwXY9JCCGe0PO+1tRmT1xyNnvDgtOYCJSvq0RPGMcU2haxHjIOEjjAtTx27HVQ
ACAEERntxv/fTv4IgScxT3F0bgMMcCeBVWqaQ5Kkf9v9P8UXHkG7zuinf4yV+f1/
+GGIiQA+/wsB2/3VtaTkkRECAwEAAaOB9DCB8TAfBgNVHSMEGDAWgBTa7WR0FJwU
PKvdmam9WyhNizzJ2DAdBgNVHQ4EFgQUfb+R16dsWkdmRHuQ1I6QckGPF8IwDgYD
VR0PAQH/BAQDAgbAMAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUH
AwgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VU
Ti1VU0VSRmlyc3QtT2JqZWN0LmNybDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUH
MAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQELBQADggEB
AFCw9d9frTPcw1NYWLzCE3V7IB1Uyro/UD+6ivRrCWPAW12L1nUac72L/0fxFdxR
FiMZMuZukk3Rxi5aHohCFMly5dcIUIpq9WRAVq4k42GXFULwLEiug+Y1PItbwo+u
jsw0UjTg+/7K/bEkaNGkESMQBv2ywiQnx9fpShyPPz7P7et1eWyOX/chtlDmJaHN
ZpQSbL/bs66H2GgDciACwn7alPNyBzxX6FUk5wWgHcSBAYJLHz8PnTOb8E/MndaF
gc/L5/1K6ZK49w1ycy3pd/lvjyh6Ph69CIbcjR4RX/dbu4d2xp5MVGHQZ9uThNox
hwOS55/j6c9aVsho4FJJlFwxggJxMIICbQIBATCBqjCBlTELMAkGA1UEBhMCVVMx
CzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMV
VGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0
cnVzdC5jb20xHTAbBgNVBAMTFFVUTi1VU0VSRmlyc3QtT2JqZWN0AhBOsIePzCQ1
NrLYyfe/OVV3MA0GCWCGSAFlAwQCAQUAoIGYMBoGCSqGSIb3DQEJAzENBgsqhkiG
9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMTYwNzI4MTEzODQ3WjArBgsqhkiG9w0B
CRACDDEcMBowGDAWBBQ2Un1Pompo+etFlvHZmrssDqdt+jAvBgkqhkiG9w0BCQQx
IgQgXBnEfFijVzb4h7n7wGBdvQhBEzRn87M67RIUdRNe6dwwDQYJKoZIhvcNAQEB
BQAEggEACcjtqph0BQ20lchE0HZYg/4oL8KuPh1Vx5LL2cVaPcj2fruoXH58577E
XFQxhZ08HsjZtYdhVokRs2vbjM/i23HVDX+IkwGuESloFXhtoAt9hKNkyhXTtWx5
tt7TEJwi+o8/SU9bFnDqPMVn5Bg+QNnnegiCJzQ4lZnmTW2JiEmL3u7XzZ21FLZ7
KT/JqgOvBY3yvWySODN1yKVdhk5FkVKxBAxBgccPQ6nwmdm0RxqbsLdoSXFuRMi5
7sUgo113xR2VuvdJzl6d4iAYdUvuSRz94xXIQMQ9L307dKZ2yTYUQTy1YcSRxsZb
kTmkisjtzbXCyfC+AYB6dnoeBp3euQ==
--{79EAC9E2-BAF9-11CE-8C82-00AA004BA90B}--
Please edit me if I am wrong.
Any e-mail client that supports it so to verify?

Ruby (Rails) email (base64) gets split at diacritics and content lost in mysql

I have a problem with my app that reads e-mails from external server using mailman gem (which is also using mail).
ruby 1.9.2p0
mail (2.3.0)
mailman (0.4.0)
actionmailer (= 3.1.3)
database.yml
production:
adapter: mysql2
encoding: utf8
Here is a simple method to receive 'mail'. I build #message_body from text_part of multipart email (for ex. with attachments) or from the whole body (decoded).
def self.receive_mail(message)
# some code here
#message_body = message.multipart? ? message.text_part.body.to_s : message.body.decoded
# some code here, to save message in database
My problem is that if the message doesn't have attachments but have diacritics, like ą ś ł ń ż ź ó ... body is split just before first diacricit.
So if body is:
"test żłóbek test"
I will get only "test " in #message_body.
My question is how to save such a message in an elegant way, so that text part is saved in database with all diacritics.
EDIT:
to make it cleaner, I get e-mails that look like this one (it's just a part of e-mail sent from gmail)
--20cf307ac4372d830104c11c8cc6
Date: Mon, 28 May 2012 20:06:16 +0200
Mime-Version: 1.0
Content-Type: text/plain;
charset=ISO-8859-2
Content-Transfer-Encoding: base64
Content-ID: <4fc3be989b76e_794650c25f6625e3#vk1057.some_domain>
dGVzdCC/s7zm8bbzsSB0ZXN0Cg==
So we have this 'body' : dGVzdCC/s7zm8bbzsSB0ZXN0Cg==
After decoding we get : 'test \xbf\xb3\xbc\xe6\xf1\xb6\xf3\xb1 test\n'
And the problem is that starting from '\xbf' data is not saved in database.
UPDATE
another example, I think this is the problem here:
irb(main):008:0* require 'base64'
=> true
irb(main):009:0> a = "test źćłżąńś"
=> "test źćłżąńś"
irb(main):010:0> b = Base64.encode64(a)
=> "dGVzdCDFusSHxYLFvMSFxYTFmw==\n"
irb(main):011:0> Base64.decode64(b)
=> "test \xC5\xBA\xC4\x87\xC5\x82\xC5\xBC\xC4\x85\xC5\x84\xC5\x9B"
see, after decode64 my diacritics are LOST, what to do to get them back?
force_encoding('utf-8')
Doesn't work because the data isn't utf-8 - your mail headers clearly states that the message body is ISO 8859-2.
Mysql2 assumes everything is utf8 but can't convert the bytes to utf8 (because ruby doesn't know the original encoding) so your non ascii characters are thrown away by mysql
For that one string you could try
body.force_encoding('ISO-8859-2').encode('utf-8')
But really you want to be working out what encoding to use from the content type header. I'm surprised the mail gem isn't doing that for you
I have the solution. Concatenation of
.force_encoding("ORIGINAL_CHARSET").encode("UTF-8")
methods on E-Mail body object is the solution.
I had to change my receive_mail() definition from previous 'one liner' to:
if message.multipart?
charset = message.text_part.content_type_parameters[:charset]
#message_body = message.text_part.body.to_s.force_encoding(charset).encode("UTF-8")
else
charset = message.content_type_parameters[:charset]
#message_body = message.body.decoded.force_encoding(charset).encode("UTF-8")
end
With this construct I can detect what was the charset of original e-mail and then force it and encode back to UTF-8. This ensures proper decoding from base64 from original to utf-8.
If anyone has more elegant solution, please share.

Rails UTF-8 response

I've got a Rails 3.2 app running on Ruby 1.9.3 that returns JSON data stored in a MongoDB database. The data seems to be stored correctly in mongo, e.g. (look at the name attribute):
{ "_id" : ObjectId("4f986cbe4c8086fdc9000002"), "created_at" : ISODate("2012-04-25T21:31:45.474Z"), "updated_at" : ISODate("2012-04-26T22:07:23.901Z"), "creator_id" : ObjectId("4f6b4d3c4c80864381000001"), "updater_id" : null, "name" : "Trädgår'n", "sort" : "tradgarn", "address" : "Nya Allén 11", "coordinates" : [ 11.9764791, 57.7045625 ], "phone" : "46031102080", "url" : "http://www.profilrestauranger.se/tradgarn/", "user_ids" : [ ] }
But when I issue a request that returns this record, I get something like this back (now look at the name attribute):
{"address":"Nya All\u00e9n 11","coordinates":[11.9764791,57.7045625],"created_at":"2012-04-25T23:31:45+02:00","id":"4f986cbe4c8086fdc9000002","name":"Tr\u00e4dg\u00e5r'n","phone":"46031102080","sort":"tradgarn","updated_at":"2012-04-27T00:07:23+02:00","url":"http://www.profilrestauranger.se/tradgarn/"}
The response headers for anyone interested:
HTTP/1.1 200 OK
Server: nginx/1.2.0
Date: Thu, 26 Apr 2012 22:41:13 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 909
Connection: keep-alive
Status: 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Max-Age: 1000
Access-Control-Allow-Headers: *,x-requested-with
X-UA-Compatible: IE=Edge
ETag: "d2a95f06bec10d8087c3188280292d3c"
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: fdd042568195df279e59affe45bdcd37
X-Runtime: 0.037134
I cannot seem to figure out why or where the encoding is getting messed up? What gives? Help? :)
The issue is indeed one of JSON UTF-8 encoding. The #to_json method is escaping unicode characters. This can be observed by something like:
user.to_json
# => "{\"created_at\":\"2012-04-19T18:48:01Z\",\"email\":\"tr\\u00e4dg\\u00e5r#example.com\",\"id\":10,\"updated_at\":\"2012-04-27T18:37:10Z\"}"
When parsed, however, this is converted back to how you would expect it. It is possible, however, to generate the JSON using JSON.generate, with which the #as_json method can be used, along with any options for the construction. This doesn't escape the unicode. To do such:
JSON.generate(user.as_json)
# => "{\"created_at\":\"2012-04-19T18:48:01Z\",\"email\":\"trädgår#example.com\",\"id\":10,\"updated_at\":\"2012-04-27T18:37:10Z\"}"
Turns out the problem I was seeing was with the gem colorful_json. I was running the JSON thru its CLI utility cjson, and it was messing up the Unicode. I reported the issue and the new version of the gem fixes this.

Fiddler add binary file data to POST

I'm try to add binary file data directly to the request body of a POST call so I can simulate a file upload. However, I tried setting a 'before request' breakpoint and using 'insert file' but I couldn't seem to get that to work. I also tried to modify CustomRules.js to inject the file but couldn't figure out how to load binary data via JScript. Is there an easy solution here?
I'm sure this is a new feature in the year since this question was answered, but thought I'd add it anyhow:
There's a blue "[Upload file]" link in Composer now on the right side under the URL textbox. This will create a full multipart/form-data request. If you use this, you'll notice in the body you now have something that looks like this:
<#INCLUDE C:\Some\Path\my-image.jpg#>
In my case, I just wanted to POST the binary file directly with no multipart junk, so I just put the <#INCLUDE ... #> magic in the request body, and that sends the binary file as the body.
In order to send multipart/form-data, this receipe will be helped.
In upper panel (Http header), set Content-Type as below. Other values are automatically resolved.
Content-Type: multipart/form-data; boundary=-------------------------acebdf13572468
And, input Response Body at the below panel as follows.
---------------------------acebdf13572468
Content-Disposition: form-data; name="description"
the_text_is_here
---------------------------acebdf13572468
Content-Disposition: form-data; name="file"; filename="123.jpg"
Content-Type: image/jpg
<#INCLUDE *C:\Users\Me\Pictures\95111c18-e969-440c-81bf-2579f29b3564.jpg*#>
---------------------------acebdf13572468--
The import rules are,
Content-Type should have two more - signs than boundary words in body.
The last of the body should be ended with two - signs.
In Fiddler script: (in Fiddler: Rules... Customize Rules), find the OnBeforeRequest function, and add a line similar to:
if (oSession.uriContains("yourdomain"))
{
oSession.LoadRequestBodyFromFile("c:\\temp\\binarycontent.dat");
}
since version 2.0, the Request Body has an "Upload File..." link that allows you to post/upload binary data.