7

I have a very rare behavior in Action Mailer, I had implement a mailer action like 5 months ago and it was working, but yesterday, for some strange reason, it crashed.

The problem

I have a mail layout, in order to use it in all my emails, in it I render an image that is attached previously by a before filter

Layout = app/views/layouts/email.html.erb

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Visionamos</title>
    <link rel="stylesheet" type="text/css" href=<%="/assets/email.css" %>>
  </head>
  <body>
   <table>
    <tr>
     <td id="head">
      <table>
       <tr class="image">
         <td><%= image_tag(attachments['visionamos.png'].url) %></td>
...
..
.

User Mailer = app/mailers/users.rb

class UsuariosMailer < ActionMailer::Base
  include AbstractController::Callbacks # include controller callbacks
  default :from => "monitoreo@visionamos.com"
  layout "mail" #Set email layout 
  before_filter :add_inline_attachments! # Add image header for all actions

  def otp_password(user, otp_key)
    @usuario = user
    @code = otp_key
    email_with_name = "#{@usuario.nombre} <#{@usuario.email}>"
    mail(:to => email_with_name, :subject => "One time password, Plataforma Visionamos")
  end

  private
   def add_inline_attachments!
   attachments.inline['visionamos.png'] = File.read("#{Rails.root}/app/assets/images/visionamos.png")
  end
end

Now, when I try to send the email I'm, getting this error

NoMethodError - undefined method `match' for nil:NilClass:
mail (2.5.4) lib/mail/utilities.rb:112:in `unbracket'
mail (2.5.4) lib/mail/part.rb:29:in `cid'
mail (2.5.4) lib/mail/part.rb:33:in `url'
app/views/layouts/mail.html.erb:13:in     `_app_views_layouts_mail_html_erb__573848672563180413_70191451095440'
<td><%= image_tag(attachments['visionamos.png'].url) %></td>

But the image is attached to the email

>> attachments['visionamos.png']
=> #<Mail::Part:70191451538040, Multipart: false, Headers: <Content-Type: image/png;   filename="visionamos.png">, <Content-Transfer-Encoding: binary>, <Content-Disposition: inline; filename="visionamos.png">, <content-id: >>

My DevEnv

Mac with Maverics Ruby 2.0 + Rails 3.2.16

Plus

  • The email is working in my amazon ec2 instance, in my coworkers environments (ubuntu and mac)
  • If I delete the image_tag method in layout, the email is sent and the image is show as attachment, no inline

Update!!!

I've tried @Gene solution but even the email is sent, the images are normal attachments, no inline, so looking deeply, I found this

>> attachments.inline['visionamos.png'].header
=> #<Mail::Header:0x00000106cf6870 @errors=[], @charset=nil, @raw_source="", @fields=[#<Mail::Field:0x00000106cf60c8 @field=#<Mail::ContentTypeField:0x00000106cf5fd8 @charset=nil, @main_type="image", @sub_type="png", @parameters={"filename"=>"visionamos.png"}, @name="Content-Type", @length=nil, @tree=nil, @element=#<Mail::ContentTypeElement:0x00000106cf5d30 @main_type="image", @sub_type="png", @parameters=[{"filename"=>"visionamos.png"}]>, @value="image/png; filename=\"visionamos.png\"", @filename="visionamos.png">, @field_order_id=23>, #<Mail::Field:0x00000106d17390 @field=#<Mail::ContentTransferEncodingField:0x00000106d172a0 @charset=nil, @name="Content-Transfer-Encoding", @length=nil, @tree=nil, @element=#<Mail::ContentTransferEncodingElement:0x00000106d16ff8 @encoding="binary">, @value="binary">, @field_order_id=24>, #<Mail::Field:0x00000106d14a78 @field=#<Mail::ContentDispositionField:0x00000106d14960 @charset=nil, @name="Content-Disposition", @length=nil, @tree=nil, @element=#<Mail::ContentDispositionElement:0x00000106d145c8 @disposition_type="inline", @parameters=[{"filename"=>"visionamos.png"}]>, @value="inline; filename=\"visionamos.png\"", @parameters={"filename"=>"visionamos.png"}, @filename="visionamos.png">, @field_order_id=26>, #<Mail::Field:0x00000106d3e8f0 @field=#<Mail::UnstructuredField:0x00000106d5ef60 @errors=[["content-id", nil, #<Mail::Field::ParseError: Mail::MessageIdsElement can not parse |<52fe636fae8a6_686085098c087130@MacBook Pro de Ruben.mail>|

Reason was: Expected one of !, #, $, %, &, ', *, +, -, /, =, ?, ^, _, `, {, |, }, ~, @, ., ", > at line 1, column 40 (byte 40) after <52fe636fae8a6_686085098c087130@MacBook>]], @charset=#, @name="content-id", @length=nil, @tree=nil, @element=nil, @value="">, @field_order_id=100>]>

The interesting part is

 #<Mail::Field::ParseError: Mail::MessageIdsElement can not parse |<52fe636fae8a6_686085098c087130@MacBook Pro de Ruben.mail>|

 Reason was: Expected one of !, #, $, %, &, ', *, +, -, /, =, ?, ^, _, `, {, |, }, ~, @, ., ", > at line 1, column 40 (byte 40) after <52fe636fae8a6_686085098c087130@MacBook>]],

Error

rderoldan1
  • 3,517
  • 26
  • 33
  • Just a random guess: `attachments.inline['visionamos.png'] = {content: File.read("#{Rails.root}/app/assets/images/visionamos.png"), content_id: 'logo'}` – bliof Feb 12 '14 at 22:07
  • @bliof, I would try your solution, but, do you think it can add the url method to the inline attachment? tnks – rderoldan1 Feb 13 '14 at 20:55
  • It is like @Gene said, there is a [header called `content-id`](https://github.com/mikel/mail/blob/2.5.3/lib/mail/part.rb) that needs to be set (by default it is an empty string). The 'but' is that it is not set for some reason, so by setting it manually it should work. (Note: the url is `"cid:#{cid}"` and the cid is `uri_escape(unbracket(content_id))` [`unbracket` removes things like '<' and '>']) – bliof Feb 14 '14 at 16:16
  • @bliof Can you read the update in my question after try your solution' – rderoldan1 Feb 14 '14 at 19:00
  • Could you try with `content_id: ''`, `content_id: ''` and with `content_id: ''` – bliof Feb 14 '14 at 19:33
  • @bliof, thanks for your support, Gene got the answer, take a look ;) – rderoldan1 Feb 15 '14 at 16:34

2 Answers2

4

I looked at the mail source.

This error can only occur if the content id field is nil. However calling .url should be setting the content id to an empty string unless has_content_id? is returning true, meaning there's already a content id field in the multipart header.

This is not happening, so we must have a strange case where the header object is reporting has_content_id? true yet is returning a content_id of nil.

Try setting the content id field explicitly just after you set the graphic.

attachments['visionamos.png'].header['content-id'] = 'logo.graphic'

If this works, there's still the puzzle of why it's necessary. Did you make any other changes to mailer configuration or code? Did you upgrade any gems?

Addition responding to question edit

The header parser seems to be failing because there are spaces in the id ...@MacBook Pro de Ruben.mail. Try re-naming the computer with no spaces! I guess this constitutes a bug in mail. Spaces should be elided or replaced with a legal character.

My guess is that this will also fix the original problem, and you won't need to set the content-id manually any more. Hence another guess: you changed machine name or moved development to a new machine. and that's when the bug appeared!

Gene
  • 46,253
  • 4
  • 58
  • 96
  • I will try your solution in a couple of minutes, thanks for your support – rderoldan1 Feb 14 '14 at 16:31
  • I tried your solution, so, the email is sent, but the images are sent like normal attachment not as inline, but, debugging more I saw this `@errors= ..... Mail::MessageIdsElement can not parse .....` I will update my question – rderoldan1 Feb 14 '14 at 18:47
  • @rderoldan1 In response to your edit, the parser seems to be failing because there is a space in the id `@MacBook Pro de Ruben.mail`. You should re-name the computer something with no spaces in it! I guess this constitutes a bug in `mail`. – Gene Feb 14 '14 at 22:30
  • OHHHH MAN, Your save my lifeeeee!, – rderoldan1 Feb 15 '14 at 16:30
  • @rderoldan1 I looked at the `mail` source again. It uses `Socket.gethostname` to get the machine name. This returns the local network name, which should have no spaces in it. What is your Mac's network setup? – Gene Feb 15 '14 at 23:12
  • 1
    Fixing my hostname fixed the problem `sudo scutil --set HostName hostname-without-spaces.local` – Harm de Wit Apr 18 '14 at 10:46
1
sudo scutil --set HostName 'mymachine'

fixed this for me.

scutil --get HostName

was returning (not set)

Michael Baldry
  • 1,990
  • 2
  • 14
  • 28