How can I parse Delivered-To headers? - ruby-on-rails

I am trying to parse an email in Ruby on Rails that is an attachment? I am not to worried about the regular expression, but more so the method I use to get the parsed output. I am looking to do this without any mail parsing gems. The code below appears to work, is this the correct way?
model.rb
def parse_delivered_to
str = File.read("public/emails/email.txt").to_s
delivered_to = str.match(/(Delivered-To: )[\w+\-.]+#[a-z\d\-.]+\.+[a-z]+[a-z]+[a-z]/i)
end
show.html.erb
<%= #email.parse_delivered_to %><br>

Analysis
The email specifications allow for multiline headers, which your current expression won't match. In addition, I don't think your regular expression allows for all of the permissible address characters.
Solution
Using a variation of procmail's ^TO_ syntax should allow you to match multiline address patterns more liberally. For example:
header.scan( /^Delivered-To:(.*[^-a-zA-Z0-9_.])?/im ).flatten.map(&:strip)
Some Tests and Examples
header = "Delivered-To:\n Foo <foo#example.com>"
header.scan( /^Delivered-To:(.*[^-a-zA-Z0-9_.])?/im ).flatten.map(&:strip)
header.scan( /^Delivered-To:(.*[^-a-zA-Z0-9_.])?/im ).flatten.map(&:strip)
=> ["Foo <foo#example.com>"]
header.scan( /^Delivered-To:(.*[^-a-zA-Z0-9_.])?/im).
flatten.map(&:strip).to_s.scan(/[\w#.+_-]+/).grep(/#/).first.to_s
=> "foo#example.com"
'Delivered-To: foo.bar+extension#example.com'.
scan( /^Delivered-To:(.*[^-a-zA-Z0-9_.])?/im).
flatten.map(&:strip).to_s.scan(/[\w.+_-]+/)
=> ["foo.bar+extension"]
'Delivered-To: foo.bar-extension#example.com'.
scan( /^Delivered-To:(.*[^-a-zA-Z0-9_.])?/im).
flatten.map(&:strip).to_s.scan(/[\w.+_-]+/)
=> ["foo.bar-extension"]

Related

Markdown Render Newlines

I'm working on a Project and give an user the possibility to create a Post.
With loading the Post, i'm calling the markdown method, to extract links and format the text.
Now i got a Problem.
By writing "1. Example" the Output in the Post is a list.
By just writing "1.Example"_ without the whitespace between the point and the text, it'working fine.
My markdown method:
#preview = nil
options = {
autolink: true,
hard_wrap: true
}
begin
URI.extract(text, ['http', 'https', 'www']).each do |uri|
unless text.include?("<a")
text = text.gsub( uri, "#{uri}" )
#preview = LinkThumbnailer.generate(uri)
end
end
rescue OpenSSL::SSL::SSLError => e
end
renderer = Redcarpet::Render::HTML.new(options)
markdown = Redcarpet::Markdown.new(renderer)
markdown.render(text).html_safe
May you know, how to fix it.. I don't want the list, i just want the Output to be the same like the Input!
Thank you, for your time!
EDIT Added a photo to show the output.
You want to use a backslash escape in your Markdown source. As the rules explain:
Markdown allows you to use backslash escapes to generate literal characters which would otherwise have special meaning in Markdown’s formatting syntax.
Among the characters which backlash escaping supports is the dot (.). Therefore your source text should look like this:
1\. Example
Which results in this HTML:
<p>1. Example</p>
And renders as:
1. Example
By default you're going to get the list. Markdown is after all looking for syntax that it recognises in order to generate mark up.
In order to skip particular markdown features I think you're going to need to provide your own custom renderer.
If you define a new renderer:
class NoListRenderer < Redcarpet::Render::HTML
def list(contents, list_type)
contents
end
def list_item(text, list_type)
text
end
end
and use an instance of that instead of the default renderer class when you create your markdown instance it should skip the default list processing. (NB. I haven't tested this code):
renderer = NoListRenderer.new(options)
markdown = Redcarpet::Markdown.new(renderer)

Encoding parameters with multiple duplicate keys

I seem to be having the same problem as this chap here
I want to encode some parameters (for the import.io api). Effectively:
params = {
:input => "webpage/url:http://www.example.com",
:input => "keywords:some+keywords"
}
But that won't work, so I think this is the right approach:
params = { :input => ["webpage/url:http://www.example.com", "keywords:some+keywords"] }
and I want it to output
params.to_query
=> "input=webpage%2Furl%3Ahttp%3A%2F%2Fwww.example.com%2Fsome-id&input=keywords%3Asome%2Bkeywords"
unfortunately, I get
"input%5B%5D=webpage%2Furl%3Ahttp%3A%2F%2Fwww.example.com%2Fsome-id&input%5B%5D=keywords%3Asome%2Bkeywords"
It's adding [] after the input, which I believe is standard behaviour. How can I stop it doing it?
To clarify, what is the ruby or 'rails way' of dealing with url parameters that require duplicate keys?
Ran into a similar issue, there's a helpful post here Ruby Hash with duplicate keys? but briefly
params = {}.compare_by_identity
params['input'] = "webpage/url:http://www.example.com"
params['input'.dup] = "keywords:some+keywords"
then
params.to_query
returns
"input=keywords%3Asome%2Bkeywords&input=webpage%2Furl%3Ahttp%3A%2F%2Fwww.example.com"
Some characters in a url have special importance to the processing of the url: they are reserved, like keywords in a programming language. See Which characters make a URL invalid?
If you try to use these as the name or value of a parameter, it will break the uri and you'll get hard to predict results like you're seeing.
The answer is to URI escape the string, which will replace special characters with their encoded version. Rails will automatically unescape them when it gets the the request, so you don't need to worry about it.
You can escape them manually, but the best way, if you have them as a hash already, is to call .to_param on the hash.
params = { :input => ["webpage/url:http://www.example.com", "keywords:some+keywords"] }
=> {:input=>["webpage/url:http://www.example.com", "keywords:some+keywords"]}
params.to_param
=> "input%5B%5D=webpage%2Furl%3Ahttp%3A%2F%2Fwww.example.com&input%5B%5D=keywords%3Asome%2Bkeywords"

Rails and HAML: Mailto link with picture

I am trying to create a mailto link that involves clicking a picture and including some raw content from a text file into the body of the message.
The following doesn't work (haml).
= mail_to "friend#example.com" do
%img{:src=>"#{asset_path 'mail.png'}"}
I don't even know how I'd get the body preloaded in there. I know there is a :body declaration but its usage in this context eludes me.
Thoughts?
The mail_to helper only appears to accept a block in Rails 4, not previous versions. If you're using Rails 3 and can’t upgrade, you could do something like this:
- mail_link_content = capture_haml do
%img{:src=>asset_path('mail.png')}
=mail_to "friend#example.com", mail_link_content
Note that you don’t need to use a string if the contents are all interpolated (you might need to add parentheses though).
To get the body content, you just need to pass an options hash as the last argument to mail_to with a :body key:
Rails 4:
= mail_to "friend#example.com", :body => "Body text here" do
%img{:src=>asset_path('mail.png')}
Rails 3:
=mail_to "friend#example.com", mail_link_content, :body => "Body text here"

Rails escapes HTML in my plain text mails

I am using the rails 3.2.5 ActionMailer to send plain text mails. Given I have a mail view like this:
message_from_user.text.erb:
Hi <%= #recipient.name %>,
You got the following message from <%= #sender.name %>:
<%= #message %>
When #message is "quotes & ampersands", then the plain text mail contains "quotes & ampersands". So it seems like rails just treats this as a HTML view and escapes any html in order to prevent cross site scripting. However this is a plain text mail. The extension is .text.erb and ActionMailer detectes this and sets the MIME to text/plain. So I never want to escape any html in it.
I have quite a few mail templates in my application, they are all plain text. I would consider patching all of them to include <%=raw #message%> or <%= #message.html_safe %> bad style - not very DRY.
I tried varios work-arounds that included money patching Erubis. None of them seem to work. I am looking for some patch or config option or anything to disable escaping html for all .text.erb files.
Any help is greatly appreciated!
After some hours of debugging through the Erubis code, I found the following fix. You can just put it into config/initializers/fix_my_mails.rb. I've tested this with rails 3.2.7. It may work with other versions.
module ActionView
class Template
module Handlers
class ERB
def call(template)
if template.source.encoding_aware?
# First, convert to BINARY, so in case the encoding is
# wrong, we can still find an encoding tag
# (<%# encoding %>) inside the String using a regular
# expression
template_source = template.source.dup.force_encoding("BINARY")
erb = template_source.gsub(ENCODING_TAG, '')
encoding = $2
erb.force_encoding valid_encoding(template.source.dup, encoding)
# Always make sure we return a String in the default_internal
erb.encode!
else
erb = template.source.dup
end
self.class.erb_implementation.new(
erb,
:trim => (self.class.erb_trim_mode == "-"),
:escape => template.identifier =~ /\.text/ # only escape HTML templates
).src
end
end
end
end
end
It just disables HTML entities in every erb file containing .text in the file name.
Try
<%= #message.html_safe %>
You'd found this answer if you had used the search function. If that doesn't suit your needs, maybe check
https://rails.lighthouseapp.com/projects/8994/tickets/4858-actionmailer-is-html-escaping-ampersand-in-urls-in-plain-text-messages
If you haven't seen that yet, some options are discussed there

How do I encode the & symbol for batch requests?

I have a Facebook batch request that looks like this:
https://graph.facebook.com/?access_token=ACCESS_TOKEN&batch=[{"method": "GET", "relative_url": "search?q=EMAIL#ADDRESS.COM&type=user"}]
Sending this across the wire returns:
{"error"=>0, "error_description"=>"batch parameter must be a JSON array"}
If I remove the &type=user, it works fine (sends back an empty data array). I am absolutely certain that Facebook is not parsing the & character correctly. I read online somewhere that I could try encoding the & symbol to %26, however using that replacement seems to instead do a query for "EMAIL#ADDRESS.COM%26type=user". If you reverse the order of the parameters, you will see what I mean.
Any ideas how I can get the batch request parser on Facebook to recognize the & symbol without filing a bug report that will never be fixed?
EDIT:
I am using URI.encode. Here is the exact code:
queries = email_array.map { |email| { :method => "GET", :relative_url => "search?q=#{email}&type=user" } }
route = "https://graph.facebook.com/?access_token=#{token}&batch=#{URI.encode(queries.to_json)}"
res = HTTParty.post(route)
After actually playing around with this some more, I managed to reproduce the same behavior, even with a careful check and double-check that I was following the api specs correctly. This looks like a bug in facebook's batch method -- it doesn't understand ampersands in param values correctly.
Don't use a string literal to construct the json. Use to_json, like below. (Also, as an aside, don't use {} notation across more than one line, use do/end).
queries = []
email_array.each do |email|
queries << {:method => 'GET', :relative_url => "search?q=#{email}&type=user"}
end
route = "https://graph.facebook.com/?access_token=#{token}&batch=#{URI.encode(queries.to_json)}"
res = HTTParty.post(route)
Also, you can use Array#map to simply the code, like this:
queries = email_array.map { |email| {:method => 'GET', :relative_url => "search?q=#{email}&type=user"} }
route = "https://graph.facebook.com/?access_token=#{token}&batch=#{URI.encode(queries.to_json)}"
res = HTTParty.post(route)
EDIT: below is my original answer before the question was edited, for reference.
Try properly url encoding the whole parameter:
https://graph.facebook.com/?access_token=ACCESS_TOKEN&batch=[%7B%22method%22:%20%22GET%22,%20%22relative_url%22:%20%22search?q=EMAIL#ADDRESS.COM&type=user%22%7D]
In practice, you'd use URI.encode from the uri library to do this. Example:
irb(main):001:0> require 'uri'
=> true
irb(main):002:0> URI.encode('[{"method": "GET", "relative_url": "search?q=EMAIL#ADDRESS.COM&type=user"}]')
=> "[%7B%22method%22:%20%22GET%22,%20%22relative_url%22:%20%22search?q=EMAIL#ADDRESS.COM&type=user%22%7D]"
Or even better, use to_json to create your json string in the first place. Example:
irb(main):001:0> require 'rubygems'
=> true
irb(main):002:0> require 'json'
=> true
irb(main):003:0> require 'uri'
=> true
irb(main):004:0> URI.encode([{:method => 'GET', :relative_url => 'search?q=EMAIL#ADDRESS.COM&type=user'}].to_json)
=> "[%7B%22method%22:%22GET%22,%22relative_url%22:%22search?q=EMAIL#ADDRESS.COM&type=user%22%7D]"
If this helps anyone, when my AdSet batch update failed because there was an "&" in one of the interests name:
{u'id': u'6003531450398', u'name': u'Dolce & Gabbana'}
I learned that the name can be anything, and as long as the id is correct, FB will populate the name itself.

Resources