如何发送包含超过990个字符的行的CSV附件?

16

好的。我以为这个问题与我的 Rails 应用有关,但它似乎与邮件附件的更深层机制有关。

我需要从我的 Rails 应用程序发送一个 CSV 文件到一个仓库,该仓库履行我商店中下的订单。该仓库具有 CSV 的格式,讽刺的是 CSV 文件的标题行超长(1000+个字符)。

当我收到测试电子邮件并无法弄清楚是什么导致标题行中出现换行符时,我一直在猜测这是否与我的 Rails 应用有关。然而,一些搜索终于显示了原因:附加文件具有 1000 个字符的行字符限制。为什么?我不知道。看起来很荒谬,但我仍然必须以某种方式发送此 CSV 文件。

我已经尝试手动设置附件的 MIME 类型为 text/csv,但没有帮助。有人知道如何解决这个问题吗?

一些相关的 Google 结果:http://www.google.com/search?client=safari&rls=en&q=csv+wrapped+990&ie=UTF-8&oe=UTF-8

更新

我已经尝试像这样使用 base64 对附件进行编码:

    attachments['205.csv'] = {:data=> ActiveSupport::Base64.encode64(@string), :encoding => 'base64', :mime_type => 'text/csv'}

看起来并没有产生影响。我使用 Mac 上的 Sparrow 通过 me.com 帐户收到了电子邮件。我将尝试使用 Gmail 的 Web 界面。


你能否发布你的ActionMailer代码(以及CSV数据生成)?我尝试使用CSV.generate来构建超过1000个字符的行,将生成的数据添加到ActionMailer的attachments部分并发送它,但是无法复制你的问题。 - pjumble
很遗憾,即使使用您的代码,我仍然无法重现这个问题。如果您只是保存CSV而不是通过电子邮件发送它,换行符是否仍然存在?另外,请问您正在使用哪个邮件服务器、邮件客户端和CSV查看器? - pjumble
我正在通过Heroku使用SendGrid服务。在查看csv文件方面,我使用了Numbers以及简单的文本编辑器。文件中肯定存在换行符。 - CharlieMezak
如果我直接从本地的 Rails 控制台将 CSV 写入文件,输出就会很好。因此,似乎 CSV 生成本身没有问题。 - CharlieMezak
2个回答

26
这似乎是因为SendGrid邮件服务器正在修改附件内容。如果您发送带有纯文本存储MIME类型的附件(例如text/csv),它将在每990个字符处包装内容,正如您所观察到的那样。我认为这与RFC 2045/821有关:
  1. 内容传输编码头字段

    许多可通过电子邮件有用地传输的媒体类型以它们“自然”的格式表示为8位字符或二进制数据。这样的数据无法通过某些传输协议传输。例如,RFC 821(SMTP)将邮件消息限制为7位US-ASCII数据,行不超过1000个字符,包括任何尾随的CRLF行分隔符。

    因此,有必要定义一种标准机制,将这些数据编码为7位短行格式。适当标记较少受限制的格式中未编码的材料,以便直接在较少受限制的传输上使用也是可取的。本文档指定这些编码将由新的“Content-Transfer-Encoding”头字段指示。此字段尚未由任何先前的标准定义。

如果您使用Base64编码而不是默认的7位编码发送附件,则附件保持不变(没有添加换行符):

attachments['file.csv']= { :data=> ActiveSupport::Base64.encode64(@string), :encoding => 'base64' }

1
我使用了您建议的代码行来添加附件,但是当我收到它时,生成的文件仍然是一系列base64值,没有被解码。 - CharlieMezak
你发送邮件到哪个邮件服务器?你使用OSX mail.app来读取邮件吗?听起来mail.app在解码一些base64附件方面存在问题,但我目前无法访问OSX进行测试。在发布之前,我通过heroku/SendGrid将附件通过ActionMailer发送到gmail/hotmail/yahoo/smartermail帐户进行了测试,它们都正确解码了附件。你是在电子邮件中发送文本还是只有附件?此外,你是否确实添加了:encoding => 'base64'部分? - pjumble
3
不要添加:mime_type => 'text/csv'(就像你在问题更新中所做的那样),因为这会将:encoding值设置回7位,这样附件就无法解码。 - pjumble
1
就是这样,宝贝。谢谢!附件现在传输正常了!(时间限制到期后我会授予奖励。从现在起3小时) - CharlieMezak
@pjumble,这里我们手动创建电子邮件,手动添加内容边界和编码/内容类型。我尝试的是使用base-64对csv内容进行编码,并将Content-type => application/octet-stream和;charset => base-64,但仍然无法正常工作,现在电子邮件的附件已经被编码,csv文件也被编码了。你有其他提示可以帮助吗?非常感谢。 - Hilmi
显示剩余4条评论

1

你的数据中是否有可能存在导致此问题的换行符?请检查一下。

csv_for_orders(orders).lines.count == orders.count

如果是这样,一个快速/粗略的解决方法可能是更改您调用values_for_line_item(item)的位置,以values_for_line_item(item).map{|c| c.gsub(/(\r|\n)/, '')}(其他line_item调用同理)。

我已经尝试过类似的东西了,但让我试试您的具体示例,看看它们是否能得出任何结果。谢谢! - CharlieMezak
是的,看起来 csv 文件检查通过了。行数是正确的。 - CharlieMezak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接