提问人:Chiperific 提问时间:9/30/2022 更新时间:10/1/2022 访问量:169
带有 ical 附件的多部分电子邮件显示不正确
Multipart email with ical attachment displays incorrectly
问:
我不确定这是否是我的代码、ActionMailer、Mail 甚至 icalendar gem 的问题?
用户注册一个活动,他们会收到一封带有 ical 附件的电子邮件:
# app/mailers/registration_mailer.rb
class RegistrationMailer < ApplicationMailer
helper MailerHelper
def created(registration)
...
cal = Icalendar::Calendar.new
cal.event do |e|
e.dtstart = @event.start_time
e.dtend = @event.end_time
e.organizer = 'mailto:[email protected]'
e.attendee = @recipient
e.location = @location.addr_one_liner
e.summary = @summary
e.description = @description
end
cal.append_custom_property('METHOD', 'REQUEST')
mail.attachments[@attachment_title] = { mime_type: 'text/calendar', content: cal.to_ical }
mail(to: @recipient.email, subject: "[20 Liters] You registered for a filter build on #{@event.mailer_time}")
end
...
end
我有文本和 HTML 视图:
app/views/registration_mailer/created.text.erb
app/views/registration_mailer/created.html.erb
当我省略附件时,电子邮件的结构如下:
Header stuff...
Mime-Version: 1.0
Content-Type: multipart/alternative; boundary="--==_mimepart_63358693571_1146901122e"; charset=UTF-8
Content-Transfer-Encoding: 7bit
----==_mimepart_63358693571_1146901122e
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit
[the text version of the email here]
----==_mimepart_63358693571_1146901122e
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: 7bit
[the HTML version of the email here]
----==_mimepart_63358693571_1146901122e--
当附件存在时,电子邮件的结构如下:
Header stuff...
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="--==_mimepart_6335c3388b140_114924286ed"; charset=UTF-8
Content-Transfer-Encoding: 7bit
----==_mimepart_6335c3388b140_114924286ed
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit
[the text version of the email here]
----==_mimepart_6335c3388b140_114924286ed
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: 7bit
[the HTML version of the email here]
----==_mimepart_6335c3388b140_114924286ed
Content-Type: multipart/alternative; boundary="--==_mimepart_6335c3389bc30_114924287a3"; charset=UTF-8
Content-Transfer-Encoding: 7bit
----==_mimepart_6335c3389bc30_114924287a3
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit
[the text version of the email AGAIN]
----==_mimepart_6335c3389bc30_114924287a3
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: 7bit
[the HTML version of the email AGAIN]
----==_mimepart_6335c3389bc30_114924287a3--
----==_mimepart_6335c3388b140_114924286ed
Content-Type: text/calendar; charset=UTF-8
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=20Liters_filterbuild_20221011T0900.ical
Content-ID: <[email protected]>
[numbers and letters]
----==_mimepart_6335c3388b140_114924286ed--
突然变成了一棵奇怪的树:
1. Content-Type: multipart/mixed
A. Content-Type: text/plain
B. Content-Type: text/html
C. Content-Type: multipart/alternative
i. Content-Type: text/plain
ii. Content-Type: text/html
D. Content-Type: text/calendar
Rails 的邮件预览不会重现这个问题,也没有使用 Litmus 的电子邮件客户端预览(因为它似乎删除了文本部分和附件),但我假设内容类型的变形结构这不仅仅是特定于客户端的渲染问题。
我认为这来自 ActionMailer 下面的 Mail gem,它奇怪地构建了内容类型,但我在这里有点超出了我的深度。可能是 ActionMailer,我真的不知道怎么说。
我不是很精通这个,但我想我想要这个结构:
1. Content-Type: multipart/mixed
A. Content-Type: multipart/alternative
i. Content-Type: text/plain
ii. Content-Type: text/html
B. Content-Type: text/calendar
所以,两个问题:
1. 如果这是我的代码,我做错了什么?
2. 如果它不是我的代码,我可以强制使用我想要的结构吗?
我一直在梳理 ActionMailer 和 Mail 代码库,但还没有找到一种方法来手动将我的电子邮件形成到这个级别。
答:
经过更多的挖掘,我责怪 ActionMailer,尽管我仍然不确定为什么文本和 html 部分被添加两次。
我特定用途的一个猴子补丁是让 ActionMailer 和 Mail 构建对象,然后手动删除不需要的部分:mail
# app/mailers/registration_mailer.rb
...
mail.attachments[@attachment_title] = { mime_type: 'text/calendar', content: cal.to_ical }
mail(to: @recipient.email, subject: "[20 Liters] You registered for a filter build on #{@event.mailer_time}")
# PATCH: text and html parts are getting inserted in multipart/mixed (top level) as well as multipart/alternative (2nd level)
mail.parts.reject! { |part| !part.attachment? && !part.multipart? }
这仅适用于我的特定情况。如果为您创建的嵌套不同,则您的语句将需要不同。mail
reject!
就我而言,构建此结构:mail
1. Content-Type: multipart/mixed
A. Content-Type: text/plain
B. Content-Type: text/html
C. Content-Type: multipart/alternative
i. Content-Type: text/plain
ii. Content-Type: text/html
D. Content-Type: text/calendar
因此,我进入第一级 (A. - D.) 并拒绝任何非多部分且非附件的部分:
1. Content-Type: multipart/mixed
A. Content-Type: text/plain <-- not multipart, not attachment = rejected
B. Content-Type: text/html <-- not multipart, not attachment = rejected
C. Content-Type: multipart/alternative <-- is multipart, not attachment = kept
i. Content-Type: text/plain
ii. Content-Type: text/html
D. Content-Type: text/calendar <-- not multipart, is attachment = kept
如果您遇到此问题,我建议您使用调试器来检查您的对象,特别关注 .请记住,可以深度嵌套。mail
parts
parts
Mail::Part
继承自 Mail::Message,它有一些有用的方法来确定消息的“形状”:
multipart?
attachment?
attachments
has_attachments?
boundary
parts
all_parts
祝你好运。
评论