ActionMailer 3.0.7 attachments #1307

Closed
cpanderson opened this Issue May 25, 2011 · 5 comments

Comments

Projects
None yet
2 participants

Hello,

I tried due diligence in looking for answers on Ruby On Rails Groups and Stack Overflow plus searching using every possible google term I could think of but I have to submit this as I don't know what else to do.

I'm converting my 2.3.8 application to 3.0.7 and have run into a snag with forwarding emails from the app with an attachment. The attachment appears in the email as 1 byte in size and thus corrupt. The actual file is fine and Rails seems to have access to the file. I've tried multiple permutations but here's what I'm doing...

I'm fetching email from IMAP and storing it in the db. Attachments are saved to the file system and the Attachment model stores the name of the attachment and belongs to an Email. In the view there's a simple form that allows an email address to forward the email to. That's all working fine. It's just the attachment part that I'm having troubles with. This was working fine in 2.3.8 but obviously I've had to change the way the attachment is handle for 3.0.7.

def forward_email(email_id, from_address, to_address) 
    @email = Email.find(email_id) 
    @recipients = to_address 
    @from = from_address 
    @subject = @email.subject 
    @sent_on = Time.now 
    @body = @email.body + "\n\n" 
    @email.attachments.each do |file| 
        if File.exist?(file.full_path) 
            attachment :filename => file.file_name, 
                                 :content => File.read(file.full_path), 
                                 :content_type => "application/octet-stream" 
        else 
            @body += "ATTACHMENT NOT FOUND: #{file.file_name}\n\n" 
        end 
    end 
end 

If I try the attachment part like this...

attachments[file.file_name] = File.read(file.full_path) 

...then I get a text representation of the attachment at the bottom of the email. I've also tried changing many different settings for
content_type but it doesn't seem to make a difference.

Any help would be much appreciated!

Thanks,

Chris

Contributor

dv commented May 26, 2011

The problem is you specifying @Body, which apparently interferes with ActionMailer's multipart processing. I tried but apparently it's not possible to send an email using ActionMailer without a view, so you need to use views.

Try adding a view forward_email.txt.erb that contains just this:

<%=@custom_content %>

Then your code becomes

def forward_email(email_id, from_address, to_address) 
  @email = Email.find(email_id)
  @custom_content = @email.body
  @email.attachments.each do |file|
    if File.exists(file.full_path)
      attachments[file.file_name] = File.read(file.full_path)
    end
  end

  mail :to => to_address,
       :from => from_address,
       :subject => @email.subject,
       :date => Time.now
end

Since I can't find any documentation on @Body, I assume it's not supported and not actually a Rails 3 issue.

That works!

So, just to clarify, if I specify both @Body and an attachment then I need a view, otherwise @Body will work fine for just plain text notifications? Did I miss that in the documentation somewhere or is this a bug?

Thanks!

Contributor

dv commented May 27, 2011

Around line 643 in https://github.com/rails/rails/blob/master/actionmailer/lib/action_mailer/base.rb you can tell @Body is definitely not a string:

      if m.multipart?
        parts_order ||= explicit_order || headers[:parts_order]
        m.body.set_sort_order(parts_order)
        m.body.sort_parts!
      end

I believe your method probably stems from an old version of rails, which has since been changed. So it's not a bug. There's nothing in the documentation about @Body, nor is there anything in the code that jumped out at me except for the above few lines. I may be wrong, but I think it's safe to say that you shouldn't be doing it that way any longer.

However, since it's possible to render :text => "body here" in a controller, it would be nice to be able to do so in a mail as well.

Ok. Thanks again!

cpanderson closed this May 27, 2011

Contributor

dv commented May 27, 2011

Just a FYI, I tried it again, and this possibly works without a view:

def forward_email(email_id, from_address, to_address) 
  @email = Email.find(email_id)
  @email.attachments.each do |file|
    if File.exists(file.full_path)
      attachments[file.file_name] = File.read(file.full_path)
    end
  end

  mail :to => to_address,
       :from => from_address,
       :subject => @email.subject,
       :date => Time.now,
       :body => @email.body
end

Notice the :body inside the mail-hash.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment