mirror of
https://github.com/discourse/discourse.git
synced 2025-06-04 05:54:44 +08:00
FEATURE: Add attachments to outgoing emails
This feature is off by default and can can be configured with the `email_total_attachment_size_limit_kb` site setting. Co-authored-by: Maja Komel <maja.komel@gmail.com>
This commit is contained in:
@ -1812,6 +1812,7 @@ en:
|
|||||||
enable_forwarded_emails: "[BETA] Allow users to create a topic by forwarding an email in."
|
enable_forwarded_emails: "[BETA] Allow users to create a topic by forwarding an email in."
|
||||||
always_show_trimmed_content: "Always show trimmed part of incoming emails. WARNING: might reveal email addresses."
|
always_show_trimmed_content: "Always show trimmed part of incoming emails. WARNING: might reveal email addresses."
|
||||||
private_email: "Don't include content from posts or topics in email title or email body. NOTE: also disables digest emails."
|
private_email: "Don't include content from posts or topics in email title or email body. NOTE: also disables digest emails."
|
||||||
|
email_total_attachment_size_limit_kb: "Max total size of files attached to outgoing emails. Set to 0 to disable sending of attachments."
|
||||||
|
|
||||||
manual_polling_enabled: "Push emails using the API for email replies."
|
manual_polling_enabled: "Push emails using the API for email replies."
|
||||||
pop3_polling_enabled: "Poll via POP3 for email replies."
|
pop3_polling_enabled: "Poll via POP3 for email replies."
|
||||||
|
@ -1021,6 +1021,9 @@ email:
|
|||||||
enable_forwarded_emails: false
|
enable_forwarded_emails: false
|
||||||
always_show_trimmed_content: false
|
always_show_trimmed_content: false
|
||||||
private_email: false
|
private_email: false
|
||||||
|
email_total_attachment_size_limit_kb:
|
||||||
|
default: 0
|
||||||
|
max: 51200
|
||||||
|
|
||||||
files:
|
files:
|
||||||
max_image_size_kb:
|
max_image_size_kb:
|
||||||
|
@ -100,6 +100,8 @@ module Email
|
|||||||
# guards against deleted posts
|
# guards against deleted posts
|
||||||
return skip(SkippedEmailLog.reason_types[:sender_post_deleted]) unless post
|
return skip(SkippedEmailLog.reason_types[:sender_post_deleted]) unless post
|
||||||
|
|
||||||
|
add_attachments(post)
|
||||||
|
|
||||||
topic = post.topic
|
topic = post.topic
|
||||||
first_post = topic.ordered_posts.first
|
first_post = topic.ordered_posts.first
|
||||||
|
|
||||||
@ -239,6 +241,38 @@ module Email
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def add_attachments(post)
|
||||||
|
max_email_size = SiteSetting.email_total_attachment_size_limit_kb.kilobytes
|
||||||
|
return if max_email_size == 0
|
||||||
|
|
||||||
|
email_size = 0
|
||||||
|
post.uploads.each do |upload|
|
||||||
|
next if FileHelper.is_supported_image?(upload.original_filename)
|
||||||
|
next if email_size + upload.filesize > max_email_size
|
||||||
|
|
||||||
|
begin
|
||||||
|
path = if upload.local?
|
||||||
|
Discourse.store.path_for(upload)
|
||||||
|
else
|
||||||
|
Discourse.store.download(upload).path
|
||||||
|
end
|
||||||
|
|
||||||
|
@message.attachments[upload.original_filename] = File.read(path)
|
||||||
|
email_size += File.size(path)
|
||||||
|
rescue => e
|
||||||
|
Discourse.warn_exception(
|
||||||
|
e,
|
||||||
|
message: "Failed to attach file to email",
|
||||||
|
env: {
|
||||||
|
post_id: post.id,
|
||||||
|
upload_id: upload.id,
|
||||||
|
filename: upload.original_filename
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def header_value(name)
|
def header_value(name)
|
||||||
header = @message.header[name]
|
header = @message.header[name]
|
||||||
return nil unless header
|
return nil unless header
|
||||||
|
@ -351,6 +351,69 @@ describe Email::Sender do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "with attachments" do
|
||||||
|
fab!(:small_pdf) do
|
||||||
|
SiteSetting.authorized_extensions = 'pdf'
|
||||||
|
UploadCreator.new(file_from_fixtures("small.pdf", "pdf"), "small.pdf")
|
||||||
|
.create_for(Discourse.system_user.id)
|
||||||
|
end
|
||||||
|
fab!(:large_pdf) do
|
||||||
|
SiteSetting.authorized_extensions = 'pdf'
|
||||||
|
UploadCreator.new(file_from_fixtures("large.pdf", "pdf"), "large.pdf")
|
||||||
|
.create_for(Discourse.system_user.id)
|
||||||
|
end
|
||||||
|
fab!(:csv_file) do
|
||||||
|
SiteSetting.authorized_extensions = 'csv'
|
||||||
|
UploadCreator.new(file_from_fixtures("words.csv", "csv"), "words.csv")
|
||||||
|
.create_for(Discourse.system_user.id)
|
||||||
|
end
|
||||||
|
fab!(:image) do
|
||||||
|
SiteSetting.authorized_extensions = 'png'
|
||||||
|
UploadCreator.new(file_from_fixtures("logo.png", "images"), "logo.png")
|
||||||
|
.create_for(Discourse.system_user.id)
|
||||||
|
end
|
||||||
|
fab!(:post) { Fabricate(:post) }
|
||||||
|
fab!(:reply) do
|
||||||
|
raw = <<~RAW
|
||||||
|
Hello world!
|
||||||
|
#{DiscourseMarkdown.attachment_markdown(small_pdf)}
|
||||||
|
#{DiscourseMarkdown.attachment_markdown(large_pdf)}
|
||||||
|
#{DiscourseMarkdown.image_markdown(image)}
|
||||||
|
#{DiscourseMarkdown.attachment_markdown(csv_file)}
|
||||||
|
RAW
|
||||||
|
reply = Fabricate(:post, raw: raw, topic: post.topic, user: Fabricate(:user))
|
||||||
|
reply.link_post_uploads
|
||||||
|
reply
|
||||||
|
end
|
||||||
|
fab!(:notification) { Fabricate(:posted_notification, user: post.user, post: reply) }
|
||||||
|
let(:message) do
|
||||||
|
UserNotifications.user_posted(
|
||||||
|
post.user,
|
||||||
|
post: reply,
|
||||||
|
notification_type: notification.notification_type,
|
||||||
|
notification_data_hash: notification.data_hash
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "adds only non-image uploads as attachments to the email" do
|
||||||
|
SiteSetting.email_total_attachment_size_limit_kb = 10_000
|
||||||
|
Email::Sender.new(message, :valid_type).send
|
||||||
|
|
||||||
|
expect(message.attachments.length).to eq(3)
|
||||||
|
expect(message.attachments.map(&:filename))
|
||||||
|
.to contain_exactly(*[small_pdf, large_pdf, csv_file].map(&:original_filename))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "respects the size limit and attaches only files that fit into the max email size" do
|
||||||
|
SiteSetting.email_total_attachment_size_limit_kb = 40
|
||||||
|
Email::Sender.new(message, :valid_type).send
|
||||||
|
|
||||||
|
expect(message.attachments.length).to eq(2)
|
||||||
|
expect(message.attachments.map(&:filename))
|
||||||
|
.to contain_exactly(*[small_pdf, csv_file].map(&:original_filename))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'with a deleted post' do
|
context 'with a deleted post' do
|
||||||
|
|
||||||
it 'should skip sending the email' do
|
it 'should skip sending the email' do
|
||||||
|
BIN
spec/fixtures/pdf/large.pdf
vendored
Normal file
BIN
spec/fixtures/pdf/large.pdf
vendored
Normal file
Binary file not shown.
Reference in New Issue
Block a user