Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails mailer error with inline attachment

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 => "[email protected]"
  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

like image 512
rderoldan1 Avatar asked Feb 05 '14 14:02

rderoldan1


2 Answers

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!

like image 52
Gene Avatar answered Sep 27 '22 18:09

Gene


sudo scutil --set HostName 'mymachine'

fixed this for me.

scutil --get HostName

was returning (not set)

like image 26
Michael Baldry Avatar answered Sep 27 '22 18:09

Michael Baldry