Cyril Duchon-Doris
Cyril Duchon-Doris

Reputation: 14019

Rails - Attach a CSV that can be read as UTF8 with BOM in ActionMailer

In ActionMailer, I am trying to convert an array of array to a CSV and make sure the file can be read as if it were converted in UTF8 with BOM.

Previously, I was copying the content to a new file in Sublime Text, and clicking File > Save With Encoding > UTF8 with BOM otherwise the characters would end up messed up.

How can I achieve the same encoding while sending an in-memory CSV through ActionMailer (I am never writing the file to my disk)

Here is my sample code for sending the email

class CSVMailer < ApplicationMailer
  def csv(csv_as_array_of_array,
    to:,
    cc: [],
    from: '[email protected]',
    reply_to: '[email protected]',
    subject: 'Here is your CSV made with love 😘',
    filename: 'your_csv_made_with_love.csv'
  )
    attach_csv(csv_as_array_of_array, filename: filename)

    mail(
      to: to,
      cc: cc,
      subject: subject
    )
  end

  private

  def attach_csv(array_of_arrays, filename:)
    attachments[filename] = {
      mine_type: 'text/csv',
      content: CSV.generate(col_sep: ';') do |csv|
        array_of_arrays.each do |row|
          csv << row
        end
      end
    }
  end
end

Upvotes: 0

Views: 1223

Answers (1)

Cyril Duchon-Doris
Cyril Duchon-Doris

Reputation: 14019

Alright here is how I did it, assuming you are sending the following array of arrays to the mailer function

csv_as_array_of_array = [ 
  ['header1', 'header2'], 
  ['row1cell1', 'row1cell2'], 
  ...
]

a simple utility function that prepends the UTF8 bom to the csv is enough

# Small utility method
def Utility.with_utf8_bom(content)
  "\uFEFF" + content
end

So in the ActionMailer class

class CSVMailer < ApplicationMailer
  # app/mailers/csv_mailer.rb
  def send_email_with_csv(csv_as_array_of_array)
    ...
    attach_csv(csv_as_array_of_array, filename: filename)
    mail(to: ...)
  end

  private

  def attach_csv(array_of_arrays, filename:)
    attachments[filename] = {
      mine_type: 'text/csv',
      content: Utility.with_utf8_bom(
        CSV.generate(col_sep: ';', encoding: Encoding::UTF_8) do |csv|
          array_of_arrays.each do |row|
            csv << row
          end
        end
      )
    }
  end

Upvotes: 2

Related Questions