diff --git a/app/assets/javascripts/admin/controllers/modals/admin-incoming-email.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-incoming-email.js.es6
new file mode 100644
index 00000000000..bc9cd2edd8d
--- /dev/null
+++ b/app/assets/javascripts/admin/controllers/modals/admin-incoming-email.js.es6
@@ -0,0 +1,17 @@
+import ModalFunctionality from 'discourse/mixins/modal-functionality';
+import IncomingEmail from 'admin/models/incoming-email';
+import computed from 'ember-addons/ember-computed-decorators';
+import { longDate } from 'discourse/lib/formatter';
+
+export default Ember.Controller.extend(ModalFunctionality, {
+
+ @computed("model.date")
+ date(d) {
+ return longDate(d);
+ },
+
+ load(id) {
+ return IncomingEmail.find(id).then(result => this.set("model", result));
+ }
+
+});
diff --git a/app/assets/javascripts/admin/models/incoming-email.js.es6 b/app/assets/javascripts/admin/models/incoming-email.js.es6
index d0e5b43c599..82534c5c43d 100644
--- a/app/assets/javascripts/admin/models/incoming-email.js.es6
+++ b/app/assets/javascripts/admin/models/incoming-email.js.es6
@@ -14,6 +14,10 @@ IncomingEmail.reopenClass({
return this._super(attrs);
},
+ find(id) {
+ return Discourse.ajax(`/admin/email/incoming/${id}.json`);
+ },
+
findAll(filter, offset) {
filter = filter || {};
offset = offset || 0;
diff --git a/app/assets/javascripts/admin/routes/admin-email-rejected.js.es6 b/app/assets/javascripts/admin/routes/admin-email-rejected.js.es6
index 4d96868d299..a7819b31a60 100644
--- a/app/assets/javascripts/admin/routes/admin-email-rejected.js.es6
+++ b/app/assets/javascripts/admin/routes/admin-email-rejected.js.es6
@@ -5,9 +5,9 @@ export default AdminEmailIncomings.extend({
status: "rejected",
actions: {
- showRawEmail(incomingEmailId) {
- showModal('raw-email');
- this.controllerFor('raw_email').loadIncomingRawEmail(incomingEmailId);
+ showIncomingEmail(id) {
+ showModal('modals/admin-incoming-email');
+ this.controllerFor("modals/admin-incoming-email").load(id);
}
}
diff --git a/app/assets/javascripts/admin/templates/email-rejected.hbs b/app/assets/javascripts/admin/templates/email-rejected.hbs
index ea5c22112df..3c5f3cba8eb 100644
--- a/app/assets/javascripts/admin/templates/email-rejected.hbs
+++ b/app/assets/javascripts/admin/templates/email-rejected.hbs
@@ -42,7 +42,7 @@
{{email.subject}} |
- {{email.error}}
+ {{email.error}}
|
{{else}}
diff --git a/app/assets/javascripts/admin/templates/modal/admin_incoming_email.hbs b/app/assets/javascripts/admin/templates/modal/admin_incoming_email.hbs
new file mode 100644
index 00000000000..d4907a7e322
--- /dev/null
+++ b/app/assets/javascripts/admin/templates/modal/admin_incoming_email.hbs
@@ -0,0 +1,98 @@
+
+
+
+
{{model.error}}
+ {{#if model.error_description}}
+
{{model.error_description}}
+ {{/if}}
+
+
+
+
+
+{{#if model.return_path}}
+
+
+
+ {{model.return_path}}
+
+
+{{/if}}
+
+
+
+
+ {{model.message_id}}
+
+
+
+{{#if model.references}}
+
+
+
+
+ {{#each reference in model.references}}
+ - {{reference}}
+ {{/each}}
+
+
+
+{{/if}}
+
+{{#if model.in_reply_to}}
+
+
+
+ {{model.in_reply_to}}
+
+
+{{/if}}
+
+
+
+
+ {{date}}
+
+
+
+
+
+
+ {{model.from}}
+
+
+
+
+
+
+
+ {{#each to in model.to}}
+ - {{to}}
+ {{/each}}
+
+
+
+
+{{#if model.cc}}
+
+
+
+ {{model.cc}}
+
+
+{{/if}}
+
+
+
+
+ {{model.subject}}
+
+
+
+
+
+
+ {{textarea value=model.body}}
+
+
+
diff --git a/app/assets/javascripts/admin/views/modals/admin-incoming-email.js.es6 b/app/assets/javascripts/admin/views/modals/admin-incoming-email.js.es6
new file mode 100644
index 00000000000..576feff433c
--- /dev/null
+++ b/app/assets/javascripts/admin/views/modals/admin-incoming-email.js.es6
@@ -0,0 +1,7 @@
+import ModalBodyView from "discourse/views/modal-body";
+
+export default ModalBodyView.extend({
+ templateName: 'admin/templates/modal/admin_incoming_email',
+ classNames: ['incoming-emails'],
+ title: I18n.t('admin.email.incoming_emails.modal.title')
+});
diff --git a/app/assets/stylesheets/common/admin/admin_base.scss b/app/assets/stylesheets/common/admin/admin_base.scss
index 5a5df3b7381..90c8bf41c7d 100644
--- a/app/assets/stylesheets/common/admin/admin_base.scss
+++ b/app/assets/stylesheets/common/admin/admin_base.scss
@@ -1798,6 +1798,40 @@ table#user-badges {
}
}
+.incoming-emails {
+ .control-group {
+ margin: 8px 0;
+ }
+ .controls {
+ margin-left: 110px;
+ }
+ p {
+ margin: 5px 10px;
+ }
+ .error-description {
+ color: #919191;
+ font-size: 90%;
+ }
+ hr {
+ margin: 0;
+ }
+ label {
+ font-weight: bold;
+ float: left;
+ width: 100px;
+ text-align: right;
+ margin: 0 10px;
+ }
+ ul {
+ list-style: none;
+ margin: 0 10px;
+ }
+ textarea {
+ width: 95%;
+ height: 150px;
+ }
+}
+
// Mobile specific styles
// Mobile view text-inputs need some padding
.mobile-view .admin-contents {
diff --git a/app/controllers/admin/email_controller.rb b/app/controllers/admin/email_controller.rb
index c8c603e9fdb..4b685c48e24 100644
--- a/app/controllers/admin/email_controller.rb
+++ b/app/controllers/admin/email_controller.rb
@@ -57,6 +57,13 @@ class Admin::EmailController < Admin::AdminController
render json: { raw_email: incoming_email.raw }
end
+ def incoming
+ params.require(:id)
+ incoming_email = IncomingEmail.find(params[:id].to_i)
+ serializer = IncomingEmailDetailsSerializer.new(incoming_email, root: false)
+ render_json_dump(serializer)
+ end
+
private
def filter_email_logs(email_logs, params)
diff --git a/app/serializers/incoming_email_details_serializer.rb b/app/serializers/incoming_email_details_serializer.rb
new file mode 100644
index 00000000000..ac9e346caa5
--- /dev/null
+++ b/app/serializers/incoming_email_details_serializer.rb
@@ -0,0 +1,82 @@
+class IncomingEmailDetailsSerializer < ApplicationSerializer
+
+ attributes :error,
+ :error_description,
+ :return_path,
+ :date,
+ :from,
+ :to,
+ :cc,
+ :message_id,
+ :references,
+ :in_reply_to,
+ :subject,
+ :body
+
+ def initialize(incoming_email, opts)
+ super
+ @error_string = incoming_email.error
+ @mail = Mail.new(incoming_email.raw)
+ end
+
+ EMAIL_RECEIVER_ERROR_PREFIX = "Email::Receiver::".freeze
+
+ def error
+ @error_string
+ end
+
+ def error_description
+ error_name = @error_string.sub(EMAIL_RECEIVER_ERROR_PREFIX, "").underscore
+ I18n.t("emails.incoming.errors.#{error_name}")
+ end
+
+ def include_error_description?
+ @error_string[EMAIL_RECEIVER_ERROR_PREFIX]
+ end
+
+ def return_path
+ @mail.return_path
+ end
+
+ def date
+ @mail.date
+ end
+
+ def from
+ @mail.from.first.downcase
+ end
+
+ def to
+ @mail.to.map(&:downcase)
+ end
+
+ def cc
+ @mail.cc.map(&:downcase) if @mail.cc.present?
+ end
+
+ def message_id
+ @mail.message_id
+ end
+
+ def references
+ references = Email::Receiver.extract_references(@mail.references)
+ references.delete(@mail.in_reply_to) if references
+ references
+ end
+
+ def in_reply_to
+ @mail.in_reply_to
+ end
+
+ def subject
+ @mail.subject.presence || "(no subject)"
+ end
+
+ def body
+ body = @mail.text_part.decoded rescue nil
+ body ||= @mail.html_part.decoded rescue nil
+ body ||= @mail.body.decoded rescue nil
+ body.strip.truncate_words(100, escape: false)
+ end
+
+end
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 96002144e70..acd880b1bc7 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -2262,6 +2262,19 @@ en:
subject: "Subject"
error: "Error"
none: "No incoming emails found."
+ modal:
+ title: "Incoming Email Details"
+ error: "Error"
+ return_path: "Return-Path"
+ message_id: "Message-Id"
+ in_reply_to: "In-Reply-To"
+ references: "References"
+ date: "Date"
+ from: "From"
+ to: "To"
+ cc: "Cc"
+ subject: "Subject"
+ body: "Body"
filters:
from_placeholder: "from@example.com"
to_placeholder: "to@example.com"
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 71be1163da2..3cb10c0f616 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -50,6 +50,18 @@ en:
emails:
incoming:
default_subject: "Incoming email from %{email}"
+ errors:
+ empty_email_error: "Happens when the raw mail we received was blank."
+ no_message_id_error: "Happens when the mail has no 'Message-Id' header."
+ auto_generated_email_error: "Happens when the 'precedence' header is set to: list, junk, bulk or auto_reply, or when any other header contains: auto-submitted, auto-replied or auto-generated."
+ no_body_detected_error: "Happens when we couldn't extract a body and there was no attachments."
+ inactive_user_error: "Happens when the sender is not active."
+ bad_destination_address: "Happens when none of the email addresses in To/Cc/Bcc fields matched a configured incoming email address."
+ strangers_not_allowed_error: "Happens when a user tried to create a new topic in a category they're not a member of."
+ insufficient_trust_level_error: "Happens when a use tried to create a new topic in a category they don't have the required trust level for."
+ reply_user_not_matching_error: "Happens when a reply came in from a different email address the notification was sent to."
+ topic_not_found_error: "Happens when a reply came in but the related topic has been deleted."
+ topic_closed_error: "Happens when a reply came in but the related topic has been closed."
errors: &errors
format: ! '%{attribute} %{message}'
diff --git a/config/routes.rb b/config/routes.rb
index d0457c90c48..8b77b6fc916 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -125,6 +125,7 @@ Discourse::Application.routes.draw do
get "received"
get "rejected"
get "/incoming/:id/raw" => "email#raw_email"
+ get "/incoming/:id" => "email#incoming"
get "preview-digest" => "email#preview_digest"
post "handle_mail"
end
diff --git a/lib/email/receiver.rb b/lib/email/receiver.rb
index 049f7fcff75..4a5b5462d61 100644
--- a/lib/email/receiver.rb
+++ b/lib/email/receiver.rb
@@ -215,7 +215,7 @@ module Email
end
def find_related_post
- message_ids = [@mail.in_reply_to, extract_references]
+ message_ids = [@mail.in_reply_to, Email::Receiver.extract_references(@mail.references)]
message_ids.flatten!
message_ids.select!(&:present?)
message_ids.uniq!
@@ -226,11 +226,11 @@ module Email
.first
end
- def extract_references
- if Array === @mail.references
- @mail.references
- elsif @mail.references.present?
- @mail.references.split(/[\s,]/).map { |r| r.sub(/^, "").sub(/>$/, "") }
+ def self.extract_references(references)
+ if Array === references
+ references
+ elsif references.present?
+ references.split(/[\s,]/).map { |r| r.sub(/^, "").sub(/>$/, "") }
end
end