Skip to content

Commit be2cb4d

Browse files
committed
Base64 encode file attachments
By default ActionMailer tries to encode any file attachments in Base64. We've seen a problem in production where this encoding fails with an error 'invalid byte sequence in UTF-8'. We think this happens when a binary file has been uploaded with a text file extension, so the ActionMailer logic expects a text file but receives binary characters. To fix this, we can encode the files in Base64 ourselves before passing them to ActionMailer, which bypasses the failing logic. This allows us to pass these disguised binary files to ActionMailer without errors. Other files should be unaffected and the resulting emails should be otherwise identical.
1 parent 6bff018 commit be2cb4d

3 files changed

Lines changed: 27 additions & 1 deletion

File tree

app/mailers/aws_ses_form_submission_mailer.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ def submission_email(answer_content_html:, answer_content_plain_text:, submissio
1111
@csv_filename = csv_filename
1212

1313
files.each do |name, file|
14-
attachments[name] = file
14+
attachments[name] = {
15+
encoding: "base64",
16+
content: Base64.encode64(file),
17+
}
1518
end
1619

1720
mail(to: submission_email_address, subject: @subject)

spec/features/fill_in_file_upload_question_spec.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,29 @@
8484
end
8585
end
8686

87+
context "when the file unexpectedly contains binary" do
88+
# A PNG file which has been renamed to look like a TXT
89+
let(:test_file_content) { File.read("spec/fixtures/disguised_binary_file.txt") }
90+
let(:scan_status) { "NO_THREATS_FOUND" }
91+
92+
scenario "As a form filler" do
93+
when_i_visit_the_form_start_page
94+
then_i_should_see_the_first_question
95+
then_i_see_the_file_upload_component
96+
when_i_upload_a_file
97+
and_i_click_on_continue
98+
then_i_see_the_review_file_page
99+
and_i_click_on_continue
100+
then_i_should_see_the_check_your_answers_page
101+
102+
when_i_opt_out_of_email_confirmation
103+
and_i_submit_my_form
104+
then_my_form_should_be_submitted
105+
and_i_should_receive_a_reference_number
106+
and_an_email_submission_should_have_been_sent
107+
end
108+
end
109+
87110
def when_i_visit_the_form_start_page
88111
visit form_path(mode: "form", form_id: 1, form_slug: "fill-in-this-form")
89112
expect_page_to_have_no_axe_errors(page)
150 KB
Binary file not shown.

0 commit comments

Comments
 (0)