Calendar Attachments
Closed this issue · 11 comments
I've been trying to send a calendar invite as an attachment to an email. I can get the calendar invite to attach and come through, but Outlook and other mail clients fail to recognise it as a calendar invite.
I've been trying to follow the steps you mention here, but I can't get the content type and other info to pass through.
attachments.inline['v2.ics'] = { mime_type: 'text/calendar', name: 'v2.ics', content_type: 'text/calendar; charset=utf-8; method=REQUEST', content: File.read(Rails.root + 'spec/fixtures/v2.ics') }
But the actual email has it attached as:
Content-Type: text/calendar; name=v2.ics
Content-Transfer-Encoding: base64
Content-Disposition: inline; filename=v2.ics
when I think what I want is something more like:
Content-Type: text/calendar; method=REQUEST
Content-Transfer-Encoding: Base64
Content-Disposition: inline; filename=v2.ics
The wiki implies the gem is compatible with the ActionMailer API, so what am I missing?
I'm using version 0.22.1 of the gem
Hi @rmaspero,
Looks like you are explicitly attaching the invite inline (attachments.inline
bit) in your example:
attachments.inline['v2.ics'] = {
mime_type: 'text/calendar',
name: 'v2.ics',
content_type: 'text/calendar; charset=utf-8; method=REQUEST',
content: File.read(Rails.root + 'spec/fixtures/v2.ics')
}
To get the Content-Disposition
as attachment
can you please try this:
attachments['v2.ics'] = {
mime_type: 'text/calendar',
name: 'v2.ics',
content_type: 'text/calendar; charset=utf-8; method=REQUEST',
content: File.read(Rails.root + 'spec/fixtures/v2.ics')
}
Let us know how it goes!
Hi @pgraham3,
Sorry if I wasn't clear enough; my problem is not with the Content-Disposition but the additional info in the Content-Type. It doesn't seem to be passed through. e.g. the method=REQUEST
part.
Got it @rmaspero!
So it looks like this has come up recently on #97 and was solved there. I imagine your use case would be for dynamically generating ICS invites rather than attaching files directly?
Here is a quick example of working ICS attachment showing the expected 'Add to Calendar' prompt in Gmail (requires the icalendar
gem)
class CalendarMailer < ApplicationMailer
def test_ics_mail
# Create a calendar with an event (standard method)
cal = Icalendar::Calendar.new
cal.event do |e| # check icalendar gem docs for more details on the options available
e.dtstart = 1.day.from_now + 1.hour
e.dtend = 1.day.from_now + 3.hours
e.summary = "Some event"
e.description = "With a description"
end
attachments["appointment"] = { mime_type: "text/calendar", content: cal.to_ical }
mail(to: "<INVITEE@DOMAIN.COM>", subject: "Calendar attachment test")
end
end
With the icalendar gem you can dynamically generate your invites and won't have to store .ics files.
Tested in Rails console (development
environment) via CalendarMailer.test_ics_mail.deliver
![Screenshot 2023-09-01 at 3 09 00 PM](https://private-user-images.githubusercontent.com/16660335/265108337-faac4129-e332-41fc-afee-0eb5e86e3540.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjU4MjM2NDcsIm5iZiI6MTcyNTgyMzM0NywicGF0aCI6Ii8xNjY2MDMzNS8yNjUxMDgzMzctZmFhYzQxMjktZTMzMi00MWZjLWFmZWUtMGViNWU4NmUzNTQwLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA5MDglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwOTA4VDE5MjIyN1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWUxOTUwMjU0MGMxNmM3NTMyZjVmZmExYTdkOWQ4ZThlZDM4MGMxYjhmNjM2YzgzNGFlODFkNWQ5OGJmMzkxODAmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.w9XKEfoPhWxArIEln768zcsObj4wY0vW1aeZJddGgu4)
I'll also get this use case added to the wiki.
Hi @pgraham3,
Thanks, I had already looked at that issue and its solutions. My implementation already does these bits but many other email clients don't recognise an attached .ics file as an invite like Gmail's web interface.
I already have my .ics file created and am testing using one I know that my email client (MacOS Mail, and Outlook) when attached correctly automatically detect.
My problem is that Outlook and MacOS Mail appear to need the the content type to have the method request bit to show/detect the invites correctly Content-Type: text/calendar; method=REQUEST
.
Postmark doesn't seem to be passing these through when set using the ActionMailer attachments API.
Thanks for the additional info @rmaspero!
Setting the Content-Type
after initializing the attachment works for using an existing ICS file, like this:
def test_file_ics_mail
attachments["v2.ics"] = {
name: "v2.ics",
content: File.read(Rails.root + "spec/fixtures/v2.ics")
}
# MiniMime does not have an existing Content-Type for what we need by default so let's set it directly instead
# of letting MiniMime infer the Content-Type
attachments["v2.ics"].content_type = "text/calendar; charset=utf-8; method=REQUEST"
mail(to: "RECIPIENT@DOMAIN.COM", subject: "Calendar attachment test")
end
Please give that a shot.
Shows expected result in Gmail:
![Screenshot 2023-09-05 at 9 01 50 AM](https://private-user-images.githubusercontent.com/16660335/265707466-f4c4c763-86e5-4ac4-82a4-423623726541.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjU4MjM2NDcsIm5iZiI6MTcyNTgyMzM0NywicGF0aCI6Ii8xNjY2MDMzNS8yNjU3MDc0NjYtZjRjNGM3NjMtODZlNS00YWM0LTgyYTQtNDIzNjIzNzI2NTQxLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA5MDglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwOTA4VDE5MjIyN1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTg1MzA1MjA4ODc1OGEyNjQxYWI1MmY1MTI5Njk3YWY4ZGY1ZGM1ZTgyZTUwZDQyMmQyYjM1NmNkZDA1MzE3ZDMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.kq2Kzcr6bV_zc_FazsF8JnnKhOLUQKV9T-mXsC9bRKs)
Hi @pgraham3,
So despite setting that explicitly the Content-Type doesn't seem to be carried through and postmark sends:
Content-Type: text/calendar; name=v2.ics
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=v2.ics
Not sure where it is getting overwritten, but assume it is either not being passed to postmark correctly by the gem or postmark itself is rewriting the Content-Type.
@rmaspero Good point...if I send directly through the Postmark API the Content-Type
method=request
bit is preserved, as expected. It is also present if I inspect the attachment when sending using the above example code:
![Screenshot 2023-09-06 at 11 01 24 AM](https://private-user-images.githubusercontent.com/16660335/266052384-50e40376-9685-416b-bef3-4c5c826c2c3d.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjU4MjM2NDcsIm5iZiI6MTcyNTgyMzM0NywicGF0aCI6Ii8xNjY2MDMzNS8yNjYwNTIzODQtNTBlNDAzNzYtOTY4NS00MTZiLWJlZjMtNGM1YzgyNmMyYzNkLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA5MDglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwOTA4VDE5MjIyN1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWU5OTUxOTcxZjg2MjI2ZDA2YmZlNzk5MTcyNjhkYmY4OGI5YTg3NTBkNjA4NDIyMWNlMDZjOWIyZjBlMmJiZTcmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.J7ABVPio-BYK2J498VQFMLVxydiX-ns6TMS2twdjO5k)
Yet as you are seeing it is missing when I check the email source in Gmail.
Let me spend some time investigating the base postmark
gem, which handles the interactions with the Postmark API, to see if attachment headers are being modified there.
Alright I believe I found our root issue and a workaround, @rmaspero!
For background see this closed issue from 2019 in the base postmark
gem.
To get the method=request
bit of the header to propagate through, please add an initializer to monkey patch it for now:
# config/initializers/mail_attachments_patch.rb
module Mail
class Message
protected
def export_native_attachments
attachments.map do |attachment|
basics = {
"Name" => attachment.filename,
"Content" => pack_attachment_data(attachment.body.decoded),
"ContentType" => attachment.content_type
}
specials = attachment.inline? ? { "ContentID" => attachment.url } : {}
basics.update(specials)
end
end
end
end
Sending via this mailer code below resulted in the correct header appearing in Gmail/Postmark after using the above initializer:
def test_file_ics_mail
attachments["v2.ics"] = {
content: File.read("spec/fixtures/files/v2.ics"),
headers: {
"Content-Type" => "text/calendar; name=v2.ics; method=request",
}
}
mail(to: "someone@somewhere.com", subject: "Calendar attachment test")
end
![Screenshot 2023-09-06 at 2 01 24 PM](https://private-user-images.githubusercontent.com/16660335/266099901-2a2e7406-0442-48e6-8f4a-ffa00a100a73.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjU4MjM2NDcsIm5iZiI6MTcyNTgyMzM0NywicGF0aCI6Ii8xNjY2MDMzNS8yNjYwOTk5MDEtMmEyZTc0MDYtMDQ0Mi00OGU2LThmNGEtZmZhMDBhMTAwYTczLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA5MDglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwOTA4VDE5MjIyN1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWY4NGQzNzE4ZmMxZmFmYTBiNmJjNmUyYTI0ZWYzZmU3NTQzNzdlNTEwZTk1OWZlY2Q3YjBkYzJkMDBmNjk5MTAmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.cOZDl_cp_ZX9JyaZE2ayIoDm9lkQ6Rzf-83sLwT--c4)
We will work on getting that monkey patch fix implemented into the base postmark
gem. Once that is addressed you will be able to remove the patch.
Closing this as it is an issue with the base postmark
gem causing the attachment header discrepancy. Follow issue for fix status and use above workaround for now.