mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
Merge pull request #2012 from ligthyear/incoming-emails
Advanced New-Topic via Email Feature
This commit is contained in:
commit
172e517b31
@ -58,6 +58,10 @@ Discourse.EditCategoryController = Discourse.ObjectController.extend(Discourse.M
|
|||||||
return false;
|
return false;
|
||||||
}.property('saving', 'name', 'color', 'deleting'),
|
}.property('saving', 'name', 'color', 'deleting'),
|
||||||
|
|
||||||
|
emailInEnabled: function() {
|
||||||
|
return Discourse.SiteSettings.email_in;
|
||||||
|
},
|
||||||
|
|
||||||
deleteDisabled: function() {
|
deleteDisabled: function() {
|
||||||
return (this.get('deleting') || this.get('saving') || false);
|
return (this.get('deleting') || this.get('saving') || false);
|
||||||
}.property('disabled', 'saving', 'deleting'),
|
}.property('disabled', 'saving', 'deleting'),
|
||||||
|
@ -66,6 +66,8 @@ Discourse.Category = Discourse.Model.extend({
|
|||||||
permissions: this.get('permissionsForUpdate'),
|
permissions: this.get('permissionsForUpdate'),
|
||||||
auto_close_hours: this.get('auto_close_hours'),
|
auto_close_hours: this.get('auto_close_hours'),
|
||||||
position: this.get('position'),
|
position: this.get('position'),
|
||||||
|
email_in: this.get('email_in'),
|
||||||
|
email_in_allow_strangers: this.get('email_in_allow_strangers'),
|
||||||
parent_category_id: this.get('parent_category_id')
|
parent_category_id: this.get('parent_category_id')
|
||||||
},
|
},
|
||||||
type: this.get('id') ? 'PUT' : 'POST'
|
type: this.get('id') ? 'PUT' : 'POST'
|
||||||
|
@ -105,6 +105,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{{#if controller.emailInEnabled}}
|
||||||
|
<section class='field'>
|
||||||
|
<div class="email-in-fields">
|
||||||
|
<div>
|
||||||
|
<i class="fa fa-envelope-o"></i>
|
||||||
|
{{i18n category.email_in}}
|
||||||
|
{{textField value=email_in}}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="checkbox-label">
|
||||||
|
{{view Ember.Checkbox checkedBinding="email_in_allow_strangers"}}
|
||||||
|
{{i18n category.email_in_allow_strangers}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
<section class='field'>
|
<section class='field'>
|
||||||
<label>{{i18n category.position}}</label>
|
<label>{{i18n category.position}}</label>
|
||||||
<span {{action disableDefaultPosition}}>{{textField value=position disabled=defaultPosition class="position-input"}}</span>
|
<span {{action disableDefaultPosition}}>{{textField value=position disabled=defaultPosition class="position-input"}}</span>
|
||||||
|
@ -90,7 +90,7 @@ class CategoriesController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
params.permit(*required_param_keys, :position, :parent_category_id, :auto_close_hours, :permissions => [*p.try(:keys)])
|
params.permit(*required_param_keys, :position, :email_in, :email_in_allow_strangers, :parent_category_id, :auto_close_hours, :permissions => [*p.try(:keys)])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -3,11 +3,14 @@
|
|||||||
#
|
#
|
||||||
require 'net/pop'
|
require 'net/pop'
|
||||||
require_dependency 'email/receiver'
|
require_dependency 'email/receiver'
|
||||||
|
require_dependency 'email/sender'
|
||||||
|
require_dependency 'email/message_builder'
|
||||||
|
|
||||||
module Jobs
|
module Jobs
|
||||||
class PollMailbox < Jobs::Scheduled
|
class PollMailbox < Jobs::Scheduled
|
||||||
every 5.minutes
|
every 5.minutes
|
||||||
sidekiq_options retry: false
|
sidekiq_options retry: false
|
||||||
|
include Email::BuildEmailHelper
|
||||||
|
|
||||||
def execute(args)
|
def execute(args)
|
||||||
if SiteSetting.pop3s_polling_enabled?
|
if SiteSetting.pop3s_polling_enabled?
|
||||||
@ -15,6 +18,26 @@ module Jobs
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def handle_mail(mail)
|
||||||
|
begin
|
||||||
|
Email::Receiver.new(mail).process
|
||||||
|
rescue Email::Receiver::UserNotSufficientTrustLevelError => e
|
||||||
|
# inform the user about the rejection
|
||||||
|
@message = Mail::Message.new(mail)
|
||||||
|
clientMessage = RejectionMailer.send_trust_level(@message.from, @message.body)
|
||||||
|
email_sender = Email::Sender.new(clientMessage, :email_reject_trust_level)
|
||||||
|
email_sender.send
|
||||||
|
rescue Email::Receiver::ProcessingError
|
||||||
|
# all other ProcessingErrors are ok to be dropped
|
||||||
|
rescue StandardError => e
|
||||||
|
# Inform Admins about error
|
||||||
|
GroupMessage.create(Group[:admins].name, :email_error_notification,
|
||||||
|
{limit_once_per: false, message_params: {source: mail, error: e}})
|
||||||
|
ensure
|
||||||
|
mail.delete
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def poll_pop3s
|
def poll_pop3s
|
||||||
Net::POP3.enable_ssl(OpenSSL::SSL::VERIFY_NONE)
|
Net::POP3.enable_ssl(OpenSSL::SSL::VERIFY_NONE)
|
||||||
Net::POP3.start(SiteSetting.pop3s_polling_host,
|
Net::POP3.start(SiteSetting.pop3s_polling_host,
|
||||||
@ -23,9 +46,7 @@ module Jobs
|
|||||||
SiteSetting.pop3s_polling_password) do |pop|
|
SiteSetting.pop3s_polling_password) do |pop|
|
||||||
unless pop.mails.empty?
|
unless pop.mails.empty?
|
||||||
pop.each do |mail|
|
pop.each do |mail|
|
||||||
if Email::Receiver.new(mail.pop).process == Email::Receiver.results[:processed]
|
handle_mail mail.pop
|
||||||
mail.delete
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
13
app/mailers/rejection_mailer.rb
Normal file
13
app/mailers/rejection_mailer.rb
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
require_dependency 'email/message_builder'
|
||||||
|
|
||||||
|
class RejectionMailer < ActionMailer::Base
|
||||||
|
include Email::BuildEmailHelper
|
||||||
|
|
||||||
|
def send_rejection(from, body)
|
||||||
|
build_email(from, template: 'email_reject_notification', from: from, body: body)
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_trust_level(from, body, to)
|
||||||
|
build_email(from, template: 'email_reject_trust_level', to: to)
|
||||||
|
end
|
||||||
|
end
|
@ -335,6 +335,10 @@ SQL
|
|||||||
self.where(id: slug.to_i, parent_category_id: parent_category_id).includes(:featured_users).first
|
self.where(id: slug.to_i, parent_category_id: parent_category_id).includes(:featured_users).first
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.find_by_email(email)
|
||||||
|
self.where(email_in: Email.downcase(email)).first
|
||||||
|
end
|
||||||
|
|
||||||
def has_children?
|
def has_children?
|
||||||
id && Category.where(parent_category_id: id).exists?
|
id && Category.where(parent_category_id: id).exists?
|
||||||
end
|
end
|
||||||
|
@ -5,6 +5,8 @@ class CategorySerializer < BasicCategorySerializer
|
|||||||
:auto_close_hours,
|
:auto_close_hours,
|
||||||
:group_permissions,
|
:group_permissions,
|
||||||
:position,
|
:position,
|
||||||
|
:email_in,
|
||||||
|
:email_in_allow_strangers,
|
||||||
:can_delete
|
:can_delete
|
||||||
|
|
||||||
def group_permissions
|
def group_permissions
|
||||||
@ -35,4 +37,12 @@ class CategorySerializer < BasicCategorySerializer
|
|||||||
scope && scope.can_delete?(object)
|
scope && scope.can_delete?(object)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def include_email_in?
|
||||||
|
scope && scope.can_edit?(object)
|
||||||
|
end
|
||||||
|
|
||||||
|
def include_email_in_allow_strangers?
|
||||||
|
scope && scope.can_edit?(object)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -1081,6 +1081,8 @@ en:
|
|||||||
security: "Security"
|
security: "Security"
|
||||||
auto_close_label: "Auto-close topics after:"
|
auto_close_label: "Auto-close topics after:"
|
||||||
auto_close_units: "hours"
|
auto_close_units: "hours"
|
||||||
|
email_in: "Custom incoming email address:"
|
||||||
|
email_in_allow_strangers: "Accept emails from non-users (aka strangers)"
|
||||||
edit_permissions: "Edit Permissions"
|
edit_permissions: "Edit Permissions"
|
||||||
add_permission: "Add Permission"
|
add_permission: "Add Permission"
|
||||||
this_year: "this year"
|
this_year: "this year"
|
||||||
|
@ -791,6 +791,10 @@ en:
|
|||||||
pop3s_polling_host: "The host to poll for email via POP3S"
|
pop3s_polling_host: "The host to poll for email via POP3S"
|
||||||
pop3s_polling_username: "The username for the POP3S account to poll for email"
|
pop3s_polling_username: "The username for the POP3S account to poll for email"
|
||||||
pop3s_polling_password: "The password for the POP3S account to poll for email"
|
pop3s_polling_password: "The password for the POP3S account to poll for email"
|
||||||
|
email_in: "Allow users to post new topics via email"
|
||||||
|
email_in_address: "The email address the users can post new topics to. None means users can't post globally."
|
||||||
|
email_in_min_trust: "The minimum trust level an users needs to have to be allowed to post new topics via email"
|
||||||
|
email_in_category: "The category new emails are posted into"
|
||||||
enable_mailing_list_mode: "Allow users to (optionally) opt-in to mailing list mode via a user preference"
|
enable_mailing_list_mode: "Allow users to (optionally) opt-in to mailing list mode via a user preference"
|
||||||
|
|
||||||
minimum_topics_similar: "How many topics need to exist in the database before similar topics are presented."
|
minimum_topics_similar: "How many topics need to exist in the database before similar topics are presented."
|
||||||
@ -1107,6 +1111,24 @@ en:
|
|||||||
subject_template: "Import completed successfully"
|
subject_template: "Import completed successfully"
|
||||||
text_body_template: "The import was successful."
|
text_body_template: "The import was successful."
|
||||||
|
|
||||||
|
email_error_notification:
|
||||||
|
subject_template: "Error parsing email"
|
||||||
|
text_body_template: |
|
||||||
|
This is an automated message to inform you that parsing the following incoming email failed.
|
||||||
|
|
||||||
|
Please review the following message.
|
||||||
|
|
||||||
|
Error - %{error}
|
||||||
|
|
||||||
|
%{source}
|
||||||
|
|
||||||
|
email_reject_trust_level:
|
||||||
|
subject_template: "Message rejected"
|
||||||
|
text_body_template: |
|
||||||
|
The message you've send to %{to} was rejected by the system.
|
||||||
|
|
||||||
|
You do not have the required trust to post new topics to this email address.
|
||||||
|
|
||||||
too_many_spam_flags:
|
too_many_spam_flags:
|
||||||
subject_template: "New account blocked"
|
subject_template: "New account blocked"
|
||||||
text_body_template: |
|
text_body_template: |
|
||||||
|
@ -235,6 +235,14 @@ email:
|
|||||||
pop3s_polling_port: 995
|
pop3s_polling_port: 995
|
||||||
pop3s_polling_username: ''
|
pop3s_polling_username: ''
|
||||||
pop3s_polling_password: ''
|
pop3s_polling_password: ''
|
||||||
|
email_in:
|
||||||
|
default: false
|
||||||
|
client: true
|
||||||
|
email_in_address: ''
|
||||||
|
email_in_min_trust:
|
||||||
|
default: 3
|
||||||
|
enum: 'MinTrustToCreateTopicSetting'
|
||||||
|
email_in_category: -1
|
||||||
enable_mailing_list_mode:
|
enable_mailing_list_mode:
|
||||||
default: false
|
default: false
|
||||||
client: true
|
client: true
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
class AddCustomEmailInToCategories < ActiveRecord::Migration
|
||||||
|
def up
|
||||||
|
add_column :categories, :email_in, :string, null: true
|
||||||
|
add_column :categories, :email_in_allow_strangers, :boolean, default: false
|
||||||
|
add_index :categories, :email_in, unique: true
|
||||||
|
end
|
||||||
|
def down
|
||||||
|
remove_column :categories, :email_in
|
||||||
|
remove_column :categories, :email_in_allow_strangers
|
||||||
|
remove_index :categories, :email_in
|
||||||
|
end
|
||||||
|
end
|
49
docs/MAILING-LIST-SETUP.MD
Normal file
49
docs/MAILING-LIST-SETUP.MD
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
## App Setup
|
||||||
|
|
||||||
|
Acting like a Mailing list is disabled per default in Discourse. This guide shows you through the way to enable and configure it.
|
||||||
|
|
||||||
|
## Admin UI Setup
|
||||||
|
|
||||||
|
First of, you need a POP3s enabled server receiving your email. Then make sure to enable "reply_by_email_enabled" and configured the server appropriately in your Admin-Settings under "Email":
|
||||||
|

|
||||||
|
|
||||||
|
Once that is in place, you can enable the "email_in"-feature globally in the same email-section. If you provide another "email_in_address" all emails arriving in the inbox to that address will be handeled and posted to the "email_in_category" (defaults to "uncategorised"). For spam protection only users of a high trust level can post via email per default. You can change this via the "email_in_min_trust" setting.
|
||||||
|
|
||||||
|
### Per category email address
|
||||||
|
|
||||||
|
Once "email_in" is enabled globally a new configuration option appears in your category settings dialog allowing you to specify an email-address for that category. Emails going to the previously configured inbox to that email-address will be posted in this category instead of the default configuration. **Attention** User-Permissions and the minimum trust levels still apply.
|
||||||
|
|
||||||
|
Additionally, by checking the "accept non-user emails"-checkbox in the category settings, emails to the given email but from unknown email-addresses will be posted in the category by the System-User in a quoted fashion, showing the original email-address and content in the quotes.
|
||||||
|
|
||||||
|
### Troubleshooting
|
||||||
|
|
||||||
|
You might want to allow users to opt-in to receive all posts via email with the option on the bottom:
|
||||||
|

|
||||||
|
|
||||||
|
As there is no way to enforce subject lines, you might want to lower minimum topic length, too
|
||||||
|

|
||||||
|
|
||||||
|
And as some emails may have the same subject, allow duplicate titles might be another option you want to look at
|
||||||
|

|
||||||
|
|
||||||
|
## Suggested User Preferences
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
Q: Why is this needed?
|
||||||
|
|
||||||
|
A: No matter how good a forum is, sometimes members need to ask a question and all they have is their mail client.
|
||||||
|
|
||||||
|
|
||||||
|
Q: What if a message is received from an email address which doesn't belong to an approved, registered user?
|
||||||
|
|
||||||
|
A: It will be rejected, and a notification email sent to the moderator. Check your POP mailbox to see the rejected email content.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Q: Who did this?
|
||||||
|
|
||||||
|
A: @therealx, @yesthatallen and @ligthyear
|
||||||
|
|
@ -5,9 +5,12 @@
|
|||||||
module Email
|
module Email
|
||||||
class Receiver
|
class Receiver
|
||||||
|
|
||||||
def self.results
|
class ProcessingError < StandardError; end
|
||||||
@results ||= Enum.new(:unprocessable, :missing, :processed, :error)
|
class EmailUnparsableError < ProcessingError; end
|
||||||
end
|
class EmptyEmailError < ProcessingError; end
|
||||||
|
class UserNotFoundError < ProcessingError; end
|
||||||
|
class UserNotSufficientTrustLevelError < ProcessingError; end
|
||||||
|
class EmailLogNotFound < ProcessingError; end
|
||||||
|
|
||||||
attr_reader :body, :reply_key, :email_log
|
attr_reader :body, :reply_key, :email_log
|
||||||
|
|
||||||
@ -15,22 +18,51 @@ module Email
|
|||||||
@raw = raw
|
@raw = raw
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def is_in_email?
|
||||||
|
@allow_strangers = false
|
||||||
|
if SiteSetting.email_in and SiteSetting.email_in_address == @message.to.first
|
||||||
|
@category_id = SiteSetting.email_in_category.to_i
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
category = Category.find_by_email(@message.to.first)
|
||||||
|
return false if not category
|
||||||
|
|
||||||
|
@category_id = category.id
|
||||||
|
@allow_strangers = category.email_in_allow_strangers
|
||||||
|
return true
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
def process
|
def process
|
||||||
return Email::Receiver.results[:unprocessable] if @raw.blank?
|
raise EmptyEmailError if @raw.blank?
|
||||||
|
|
||||||
@message = Mail::Message.new(@raw)
|
@message = Mail::Message.new(@raw)
|
||||||
|
|
||||||
|
|
||||||
# First remove the known discourse stuff.
|
# First remove the known discourse stuff.
|
||||||
parse_body
|
parse_body
|
||||||
return Email::Receiver.results[:unprocessable] if @body.blank?
|
raise EmptyEmailError if @body.blank?
|
||||||
|
|
||||||
# Then run the github EmailReplyParser on it in case we didn't catch it
|
# Then run the github EmailReplyParser on it in case we didn't catch it
|
||||||
@body = EmailReplyParser.read(@body).visible_text.force_encoding('UTF-8')
|
@body = EmailReplyParser.read(@body).visible_text.force_encoding('UTF-8')
|
||||||
|
|
||||||
discourse_email_parser
|
discourse_email_parser
|
||||||
|
|
||||||
return Email::Receiver.results[:unprocessable] if @body.blank?
|
raise EmailUnparsableError if @body.blank?
|
||||||
|
|
||||||
|
if is_in_email?
|
||||||
|
@user = User.find_by_email(@message.from.first)
|
||||||
|
if @user.blank? and @allow_strangers
|
||||||
|
wrap_body_in_quote
|
||||||
|
@user = Discourse.system_user
|
||||||
|
end
|
||||||
|
|
||||||
|
raise UserNotFoundError if @user.blank?
|
||||||
|
raise UserNotSufficientTrustLevelError.new @user if not @user.has_trust_level?(TrustLevel.levels[SiteSetting.email_in_min_trust.to_i])
|
||||||
|
|
||||||
|
create_new_topic
|
||||||
|
else
|
||||||
@reply_key = @message.to.first
|
@reply_key = @message.to.first
|
||||||
|
|
||||||
# Extract the `reply_key` from the format the site has specified
|
# Extract the `reply_key` from the format the site has specified
|
||||||
@ -41,17 +73,20 @@ module Email
|
|||||||
|
|
||||||
# Look up the email log for the reply key
|
# Look up the email log for the reply key
|
||||||
@email_log = EmailLog.for(reply_key)
|
@email_log = EmailLog.for(reply_key)
|
||||||
return Email::Receiver.results[:missing] if @email_log.blank?
|
raise EmailLogNotFound if @email_log.blank?
|
||||||
|
|
||||||
create_reply
|
create_reply
|
||||||
|
end
|
||||||
Email::Receiver.results[:processed]
|
|
||||||
rescue
|
|
||||||
Email::Receiver.results[:error]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def wrap_body_in_quote
|
||||||
|
@body = "[quote=\"#{@message.from.first}\"]
|
||||||
|
#{@body}
|
||||||
|
[/quote]"
|
||||||
|
end
|
||||||
|
|
||||||
def parse_body
|
def parse_body
|
||||||
html = nil
|
html = nil
|
||||||
|
|
||||||
@ -131,5 +166,25 @@ module Email
|
|||||||
creator.create
|
creator.create
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def create_new_topic
|
||||||
|
# Try to post the body as a reply
|
||||||
|
topic_creator = TopicCreator.new(@user,
|
||||||
|
Guardian.new(@user),
|
||||||
|
category: @category_id,
|
||||||
|
title: @message.subject)
|
||||||
|
|
||||||
|
topic = topic_creator.create
|
||||||
|
post_creator = PostCreator.new(@user,
|
||||||
|
raw: @body,
|
||||||
|
topic_id: topic.id,
|
||||||
|
cooking_options: {traditional_markdown_linebreaks: true})
|
||||||
|
|
||||||
|
post_creator.create
|
||||||
|
EmailLog.create(email_type: "topic_via_incoming_email",
|
||||||
|
to_address: @message.to.first,
|
||||||
|
topic_id: topic.id, user_id: @user.id)
|
||||||
|
topic
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
107
spec/components/email/poll_mailbox_spec.rb
Normal file
107
spec/components/email/poll_mailbox_spec.rb
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
# -*- encoding : utf-8 -*-
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
require 'email/receiver'
|
||||||
|
require 'jobs/scheduled/poll_mailbox'
|
||||||
|
require 'email/message_builder'
|
||||||
|
|
||||||
|
describe Jobs::PollMailbox do
|
||||||
|
|
||||||
|
describe "processing email" do
|
||||||
|
|
||||||
|
let!(:poller) { Jobs::PollMailbox.new }
|
||||||
|
let!(:receiver) { mock }
|
||||||
|
let!(:email) { mock }
|
||||||
|
|
||||||
|
before do
|
||||||
|
Email::Receiver.expects(:new).with(email).returns(receiver)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "all goes fine" do
|
||||||
|
|
||||||
|
it "email gets deleted" do
|
||||||
|
receiver.expects(:process)
|
||||||
|
email.expects(:delete)
|
||||||
|
|
||||||
|
poller.handle_mail(email)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "raises Untrusted error" do
|
||||||
|
|
||||||
|
before do
|
||||||
|
receiver.expects(:process).raises(Email::Receiver::UserNotSufficientTrustLevelError)
|
||||||
|
email.expects(:delete)
|
||||||
|
|
||||||
|
Mail::Message.expects(:new).returns(email)
|
||||||
|
|
||||||
|
email.expects(:from)
|
||||||
|
email.expects(:body)
|
||||||
|
|
||||||
|
clientMessage = mock
|
||||||
|
senderMock = mock
|
||||||
|
RejectionMailer.expects(:send_trust_level).returns(clientMessage)
|
||||||
|
Email::Sender.expects(:new).with(
|
||||||
|
clientMessage, :email_reject_trust_level).returns(senderMock)
|
||||||
|
senderMock.expects(:send)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sends a reply and deletes the email" do
|
||||||
|
poller.handle_mail(email)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "raises error" do
|
||||||
|
|
||||||
|
it "deletes email on ProcessingError" do
|
||||||
|
receiver.expects(:process).raises(Email::Receiver::ProcessingError)
|
||||||
|
email.expects(:delete)
|
||||||
|
|
||||||
|
poller.handle_mail(email)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deletes email on EmailUnparsableError" do
|
||||||
|
receiver.expects(:process).raises(Email::Receiver::EmailUnparsableError)
|
||||||
|
email.expects(:delete)
|
||||||
|
|
||||||
|
poller.handle_mail(email)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deletes email on EmptyEmailError" do
|
||||||
|
receiver.expects(:process).raises(Email::Receiver::EmptyEmailError)
|
||||||
|
email.expects(:delete)
|
||||||
|
|
||||||
|
poller.handle_mail(email)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deletes email on UserNotFoundError" do
|
||||||
|
receiver.expects(:process).raises(Email::Receiver::UserNotFoundError)
|
||||||
|
email.expects(:delete)
|
||||||
|
|
||||||
|
poller.handle_mail(email)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "deletes email on EmailLogNotFound" do
|
||||||
|
receiver.expects(:process).raises(Email::Receiver::EmailLogNotFound)
|
||||||
|
email.expects(:delete)
|
||||||
|
|
||||||
|
poller.handle_mail(email)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
it "informs admins on any other error" do
|
||||||
|
receiver.expects(:process).raises(TypeError)
|
||||||
|
email.expects(:delete)
|
||||||
|
GroupMessage.expects(:create) do |args|
|
||||||
|
args[0].should eq "admins"
|
||||||
|
args[1].shouled eq :email_error_notification
|
||||||
|
args[2].message_params.source.should eq email
|
||||||
|
args[2].message_params.error.should_be instance_of(TypeError)
|
||||||
|
end
|
||||||
|
|
||||||
|
poller.handle_mail(email)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
@ -7,25 +7,16 @@ describe Email::Receiver do
|
|||||||
|
|
||||||
before do
|
before do
|
||||||
SiteSetting.stubs(:reply_by_email_address).returns("reply+%{reply_key}@appmail.adventuretime.ooo")
|
SiteSetting.stubs(:reply_by_email_address).returns("reply+%{reply_key}@appmail.adventuretime.ooo")
|
||||||
end
|
SiteSetting.stubs(:email_in).returns(false)
|
||||||
|
|
||||||
describe "exception raised" do
|
|
||||||
it "returns error if it encountered an error processing" do
|
|
||||||
receiver = Email::Receiver.new("some email")
|
|
||||||
def receiver.parse_body
|
|
||||||
raise "ERROR HAPPENED!"
|
|
||||||
end
|
|
||||||
expect(receiver.process).to eq(Email::Receiver.results[:error])
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'invalid emails' do
|
describe 'invalid emails' do
|
||||||
it "returns unprocessable if the message is blank" do
|
it "raises EmptyEmailError if the message is blank" do
|
||||||
expect(Email::Receiver.new("").process).to eq(Email::Receiver.results[:unprocessable])
|
expect { Email::Receiver.new("").process }.to raise_error(Email::Receiver::EmptyEmailError)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns unprocessable if the message is not an email" do
|
it "raises EmailUnparsableError if the message is not an email" do
|
||||||
expect(Email::Receiver.new("asdf" * 30).process).to eq(Email::Receiver.results[:unprocessable])
|
expect { Email::Receiver.new("asdf" * 30).process}.to raise_error(Email::Receiver::EmptyEmailError)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -34,7 +25,7 @@ describe Email::Receiver do
|
|||||||
let(:receiver) { Email::Receiver.new(reply_below) }
|
let(:receiver) { Email::Receiver.new(reply_below) }
|
||||||
|
|
||||||
it "processes correctly" do
|
it "processes correctly" do
|
||||||
receiver.process
|
expect { receiver.process}.to raise_error(Email::Receiver::ProcessingError)
|
||||||
expect(receiver.body).to eq(
|
expect(receiver.body).to eq(
|
||||||
"So presumably all the quoted garbage and my (proper) signature will get
|
"So presumably all the quoted garbage and my (proper) signature will get
|
||||||
stripped from my reply?")
|
stripped from my reply?")
|
||||||
@ -46,7 +37,7 @@ stripped from my reply?")
|
|||||||
let(:receiver) { Email::Receiver.new(reply_below) }
|
let(:receiver) { Email::Receiver.new(reply_below) }
|
||||||
|
|
||||||
it "processes correctly" do
|
it "processes correctly" do
|
||||||
receiver.process
|
expect { receiver.process}.to raise_error(Email::Receiver::ProcessingError)
|
||||||
expect(receiver.body).to eq("The EC2 instance - I've seen that there tends to be odd and " +
|
expect(receiver.body).to eq("The EC2 instance - I've seen that there tends to be odd and " +
|
||||||
"unrecommended settings on the Bitnami installs that I've checked out.")
|
"unrecommended settings on the Bitnami installs that I've checked out.")
|
||||||
end
|
end
|
||||||
@ -57,7 +48,7 @@ stripped from my reply?")
|
|||||||
let(:receiver) { Email::Receiver.new(attachment) }
|
let(:receiver) { Email::Receiver.new(attachment) }
|
||||||
|
|
||||||
it "processes correctly" do
|
it "processes correctly" do
|
||||||
expect(receiver.process).to eq(Email::Receiver.results[:unprocessable])
|
expect { receiver.process}.to raise_error(Email::Receiver::EmptyEmailError)
|
||||||
expect(receiver.body).to be_blank
|
expect(receiver.body).to be_blank
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -67,7 +58,7 @@ stripped from my reply?")
|
|||||||
let(:receiver) { Email::Receiver.new(dutch) }
|
let(:receiver) { Email::Receiver.new(dutch) }
|
||||||
|
|
||||||
it "processes correctly" do
|
it "processes correctly" do
|
||||||
receiver.process
|
expect { receiver.process}.to raise_error(Email::Receiver::ProcessingError)
|
||||||
expect(receiver.body).to eq("Dit is een antwoord in het Nederlands.")
|
expect(receiver.body).to eq("Dit is een antwoord in het Nederlands.")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -78,7 +69,7 @@ stripped from my reply?")
|
|||||||
|
|
||||||
it "processes correctly" do
|
it "processes correctly" do
|
||||||
I18n.expects(:t).with('user_notifications.previous_discussion').returns('כלטוב')
|
I18n.expects(:t).with('user_notifications.previous_discussion').returns('כלטוב')
|
||||||
receiver.process
|
expect { receiver.process}.to raise_error(Email::Receiver::ProcessingError)
|
||||||
expect(receiver.body).to eq("שלום")
|
expect(receiver.body).to eq("שלום")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -89,7 +80,7 @@ stripped from my reply?")
|
|||||||
|
|
||||||
it "processes correctly" do
|
it "processes correctly" do
|
||||||
I18n.expects(:t).with('user_notifications.previous_discussion').returns('媽!我上電視了!')
|
I18n.expects(:t).with('user_notifications.previous_discussion').returns('媽!我上電視了!')
|
||||||
receiver.process
|
expect { receiver.process}.to raise_error(Email::Receiver::ProcessingError)
|
||||||
expect(receiver.body).to eq("媽!我上電視了!")
|
expect(receiver.body).to eq("媽!我上電視了!")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -99,7 +90,7 @@ stripped from my reply?")
|
|||||||
let(:receiver) { Email::Receiver.new(wrote) }
|
let(:receiver) { Email::Receiver.new(wrote) }
|
||||||
|
|
||||||
it "removes via lines if we know them" do
|
it "removes via lines if we know them" do
|
||||||
receiver.process
|
expect { receiver.process}.to raise_error(Email::Receiver::ProcessingError)
|
||||||
expect(receiver.body).to eq("Hello this email has content!")
|
expect(receiver.body).to eq("Hello this email has content!")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -109,7 +100,7 @@ stripped from my reply?")
|
|||||||
let(:receiver) { Email::Receiver.new(wrote) }
|
let(:receiver) { Email::Receiver.new(wrote) }
|
||||||
|
|
||||||
it "processes correctly" do
|
it "processes correctly" do
|
||||||
receiver.process
|
expect { receiver.process}.to raise_error(Email::Receiver::ProcessingError)
|
||||||
expect(receiver.body).to eq("Thanks!")
|
expect(receiver.body).to eq("Thanks!")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -119,7 +110,7 @@ stripped from my reply?")
|
|||||||
let(:receiver) { Email::Receiver.new(previous) }
|
let(:receiver) { Email::Receiver.new(previous) }
|
||||||
|
|
||||||
it "processes correctly" do
|
it "processes correctly" do
|
||||||
receiver.process
|
expect { receiver.process}.to raise_error(Email::Receiver::ProcessingError)
|
||||||
expect(receiver.body).to eq("This will not include the previous discussion that is present in this email.")
|
expect(receiver.body).to eq("This will not include the previous discussion that is present in this email.")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -129,7 +120,7 @@ stripped from my reply?")
|
|||||||
let(:receiver) { Email::Receiver.new(paragraphs) }
|
let(:receiver) { Email::Receiver.new(paragraphs) }
|
||||||
|
|
||||||
it "processes correctly" do
|
it "processes correctly" do
|
||||||
receiver.process
|
expect { receiver.process}.to raise_error(Email::Receiver::ProcessingError)
|
||||||
expect(receiver.body).to eq(
|
expect(receiver.body).to eq(
|
||||||
"Is there any reason the *old* candy can't be be kept in silos while the new candy
|
"Is there any reason the *old* candy can't be be kept in silos while the new candy
|
||||||
is imported into *new* silos?
|
is imported into *new* silos?
|
||||||
@ -160,10 +151,8 @@ greatest show ever created. Everyone should watch it.
|
|||||||
EmailLog.expects(:for).returns(nil)
|
EmailLog.expects(:for).returns(nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
let!(:result) { receiver.process }
|
it "raises EmailLogNotFoundError" do
|
||||||
|
expect{ receiver.process }.to raise_error(Email::Receiver::EmailLogNotFound)
|
||||||
it "returns missing" do
|
|
||||||
expect(result).to eq(Email::Receiver.results[:missing])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -184,10 +173,6 @@ greatest show ever created. Everyone should watch it.
|
|||||||
|
|
||||||
let!(:result) { receiver.process }
|
let!(:result) { receiver.process }
|
||||||
|
|
||||||
it "returns a processed result" do
|
|
||||||
expect(result).to eq(Email::Receiver.results[:processed])
|
|
||||||
end
|
|
||||||
|
|
||||||
it "extracts the body" do
|
it "extracts the body" do
|
||||||
expect(receiver.body).to eq(reply_body)
|
expect(receiver.body).to eq(reply_body)
|
||||||
end
|
end
|
||||||
@ -204,5 +189,282 @@ greatest show ever created. Everyone should watch it.
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "processes a valid incoming email" do
|
||||||
|
before do
|
||||||
|
SiteSetting.stubs(:email_in_address).returns("discourse-in@appmail.adventuretime.ooo")
|
||||||
|
SiteSetting.stubs(:email_in_category).returns("42")
|
||||||
|
SiteSetting.stubs(:email_in).returns(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:incoming_email) { File.read("#{Rails.root}/spec/fixtures/emails/valid_incoming.eml") }
|
||||||
|
let(:receiver) { Email::Receiver.new(incoming_email) }
|
||||||
|
let(:user) { Fabricate.build(:user, id: 3456) }
|
||||||
|
let(:subject) { "We should have a post-by-email-feature." }
|
||||||
|
let(:email_body) {
|
||||||
|
"Hey folks,
|
||||||
|
|
||||||
|
I was thinking. Wouldn't it be great if we could post topics via email? Yes it would!
|
||||||
|
|
||||||
|
Jakie" }
|
||||||
|
|
||||||
|
describe "email from non user" do
|
||||||
|
|
||||||
|
before do
|
||||||
|
User.expects(:find_by_email).returns(nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises user not found error" do
|
||||||
|
expect { receiver.process }.to raise_error(Email::Receiver::UserNotFoundError)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "email from untrusted user" do
|
||||||
|
before do
|
||||||
|
User.expects(:find_by_email).with(
|
||||||
|
"jake@adventuretime.ooo").returns(user)
|
||||||
|
SiteSetting.stubs(:email_in_min_trust).returns(TrustLevel.levels[:elder].to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises untrusted user error" do
|
||||||
|
expect { receiver.process }.to raise_error(Email::Receiver::UserNotSufficientTrustLevelError)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "with proper user" do
|
||||||
|
|
||||||
|
before do
|
||||||
|
SiteSetting.stubs(:email_in_min_trust).returns(TrustLevel.levels[:newuser].to_s)
|
||||||
|
User.expects(:find_by_email).with(
|
||||||
|
"jake@adventuretime.ooo").returns(user)
|
||||||
|
|
||||||
|
topic_creator = mock()
|
||||||
|
TopicCreator.expects(:new).with(instance_of(User),
|
||||||
|
instance_of(Guardian),
|
||||||
|
has_entries(title: subject,
|
||||||
|
category: 42))
|
||||||
|
.returns(topic_creator)
|
||||||
|
|
||||||
|
topic_creator.expects(:create).returns(topic_creator)
|
||||||
|
topic_creator.expects(:id).twice.returns(12345)
|
||||||
|
|
||||||
|
|
||||||
|
post_creator = mock
|
||||||
|
PostCreator.expects(:new).with(instance_of(User),
|
||||||
|
has_entries(raw: email_body,
|
||||||
|
topic_id: 12345,
|
||||||
|
cooking_options: {traditional_markdown_linebreaks: true}))
|
||||||
|
.returns(post_creator)
|
||||||
|
|
||||||
|
post_creator.expects(:create)
|
||||||
|
|
||||||
|
EmailLog.expects(:create).with(has_entries(
|
||||||
|
email_type: 'topic_via_incoming_email',
|
||||||
|
to_address: "discourse-in@appmail.adventuretime.ooo",
|
||||||
|
user_id: 3456,
|
||||||
|
topic_id: 12345
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
let!(:result) { receiver.process }
|
||||||
|
|
||||||
|
it "extracts the body" do
|
||||||
|
expect(receiver.body).to eq(email_body)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
describe "processes an email to a category" do
|
||||||
|
before do
|
||||||
|
SiteSetting.stubs(:email_in_address).returns("")
|
||||||
|
SiteSetting.stubs(:email_in_category).returns("42")
|
||||||
|
SiteSetting.stubs(:email_in).returns(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:incoming_email) { File.read("#{Rails.root}/spec/fixtures/emails/valid_incoming.eml") }
|
||||||
|
let(:receiver) { Email::Receiver.new(incoming_email) }
|
||||||
|
let(:user) { Fabricate.build(:user, id: 3456) }
|
||||||
|
let(:category) { Fabricate.build(:category, id: 10) }
|
||||||
|
let(:subject) { "We should have a post-by-email-feature." }
|
||||||
|
let(:email_body) {
|
||||||
|
"Hey folks,
|
||||||
|
|
||||||
|
I was thinking. Wouldn't it be great if we could post topics via email? Yes it would!
|
||||||
|
|
||||||
|
Jakie" }
|
||||||
|
|
||||||
|
describe "category not found" do
|
||||||
|
|
||||||
|
before do
|
||||||
|
Category.expects(:find_by_email).returns(nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises EmailLogNotFoundError" do
|
||||||
|
expect{ receiver.process }.to raise_error(Email::Receiver::EmailLogNotFound)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "email from non user" do
|
||||||
|
|
||||||
|
before do
|
||||||
|
User.expects(:find_by_email).returns(nil)
|
||||||
|
Category.expects(:find_by_email).with(
|
||||||
|
"discourse-in@appmail.adventuretime.ooo").returns(category)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises UserNotFoundError" do
|
||||||
|
expect{ receiver.process }.to raise_error(Email::Receiver::UserNotFoundError)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "email from untrusted user" do
|
||||||
|
before do
|
||||||
|
User.expects(:find_by_email).with(
|
||||||
|
"jake@adventuretime.ooo").returns(user)
|
||||||
|
Category.expects(:find_by_email).with(
|
||||||
|
"discourse-in@appmail.adventuretime.ooo").returns(category)
|
||||||
|
SiteSetting.stubs(:email_in_min_trust).returns(TrustLevel.levels[:elder].to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises untrusted user error" do
|
||||||
|
expect { receiver.process }.to raise_error(Email::Receiver::UserNotSufficientTrustLevelError)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "with proper user" do
|
||||||
|
|
||||||
|
before do
|
||||||
|
SiteSetting.stubs(:email_in_min_trust).returns(
|
||||||
|
TrustLevel.levels[:newuser].to_s)
|
||||||
|
User.expects(:find_by_email).with(
|
||||||
|
"jake@adventuretime.ooo").returns(user)
|
||||||
|
Category.expects(:find_by_email).with(
|
||||||
|
"discourse-in@appmail.adventuretime.ooo").returns(category)
|
||||||
|
|
||||||
|
topic_creator = mock()
|
||||||
|
TopicCreator.expects(:new).with(instance_of(User),
|
||||||
|
instance_of(Guardian),
|
||||||
|
has_entries(title: subject,
|
||||||
|
category: 10)) # Make sure it is posted to the right category
|
||||||
|
.returns(topic_creator)
|
||||||
|
|
||||||
|
topic_creator.expects(:create).returns(topic_creator)
|
||||||
|
topic_creator.expects(:id).twice.returns(12345)
|
||||||
|
|
||||||
|
|
||||||
|
post_creator = mock
|
||||||
|
PostCreator.expects(:new).with(instance_of(User),
|
||||||
|
has_entries(raw: email_body,
|
||||||
|
topic_id: 12345,
|
||||||
|
cooking_options: {traditional_markdown_linebreaks: true}))
|
||||||
|
.returns(post_creator)
|
||||||
|
|
||||||
|
post_creator.expects(:create)
|
||||||
|
|
||||||
|
EmailLog.expects(:create).with(has_entries(
|
||||||
|
email_type: 'topic_via_incoming_email',
|
||||||
|
to_address: "discourse-in@appmail.adventuretime.ooo",
|
||||||
|
user_id: 3456,
|
||||||
|
topic_id: 12345
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
let!(:result) { receiver.process }
|
||||||
|
|
||||||
|
it "extracts the body" do
|
||||||
|
expect(receiver.body).to eq(email_body)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
describe "processes an unknown email sender to category" do
|
||||||
|
before do
|
||||||
|
SiteSetting.stubs(:email_in_address).returns("")
|
||||||
|
SiteSetting.stubs(:email_in_category).returns("42")
|
||||||
|
SiteSetting.stubs(:email_in).returns(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:incoming_email) { File.read("#{Rails.root}/spec/fixtures/emails/valid_incoming.eml") }
|
||||||
|
let(:receiver) { Email::Receiver.new(incoming_email) }
|
||||||
|
let(:non_inbox_email_category) { Fabricate.build(:category, id: 20, email_in_allow_strangers: false) }
|
||||||
|
let(:public_inbox_email_category) { Fabricate.build(:category, id: 25, email_in_allow_strangers: true) }
|
||||||
|
let(:subject) { "We should have a post-by-email-feature." }
|
||||||
|
let(:email_body) { "[quote=\"jake@adventuretime.ooo\"]
|
||||||
|
Hey folks,
|
||||||
|
|
||||||
|
I was thinking. Wouldn't it be great if we could post topics via email? Yes it would!
|
||||||
|
|
||||||
|
Jakie
|
||||||
|
[/quote]" }
|
||||||
|
|
||||||
|
describe "to disabled category" do
|
||||||
|
before do
|
||||||
|
User.expects(:find_by_email).with(
|
||||||
|
"jake@adventuretime.ooo").returns(nil)
|
||||||
|
Category.expects(:find_by_email).with(
|
||||||
|
"discourse-in@appmail.adventuretime.ooo").returns(non_inbox_email_category)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises UserNotFoundError" do
|
||||||
|
expect{ receiver.process }.to raise_error(Email::Receiver::UserNotFoundError)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "to enabled category" do
|
||||||
|
|
||||||
|
before do
|
||||||
|
User.expects(:find_by_email).with(
|
||||||
|
"jake@adventuretime.ooo").returns(nil)
|
||||||
|
Category.expects(:find_by_email).with(
|
||||||
|
"discourse-in@appmail.adventuretime.ooo").returns(public_inbox_email_category)
|
||||||
|
|
||||||
|
topic_creator = mock()
|
||||||
|
TopicCreator.expects(:new).with(Discourse.system_user,
|
||||||
|
instance_of(Guardian),
|
||||||
|
has_entries(title: subject,
|
||||||
|
category: 25)) # Make sure it is posted to the right category
|
||||||
|
.returns(topic_creator)
|
||||||
|
|
||||||
|
topic_creator.expects(:create).returns(topic_creator)
|
||||||
|
topic_creator.expects(:id).twice.returns(135)
|
||||||
|
|
||||||
|
|
||||||
|
post_creator = mock
|
||||||
|
PostCreator.expects(:new).with(Discourse.system_user,
|
||||||
|
has_entries(raw: email_body,
|
||||||
|
topic_id: 135,
|
||||||
|
cooking_options: {traditional_markdown_linebreaks: true}))
|
||||||
|
.returns(post_creator)
|
||||||
|
|
||||||
|
post_creator.expects(:create)
|
||||||
|
|
||||||
|
EmailLog.expects(:create).with(has_entries(
|
||||||
|
email_type: 'topic_via_incoming_email',
|
||||||
|
to_address: "discourse-in@appmail.adventuretime.ooo",
|
||||||
|
user_id: Discourse.system_user.id,
|
||||||
|
topic_id: 135
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
let!(:result) { receiver.process }
|
||||||
|
|
||||||
|
it "extracts the body" do
|
||||||
|
expect(receiver.body).to eq(email_body)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -2,4 +2,3 @@ Fabricator(:category) do
|
|||||||
name { sequence(:name) { |n| "Amazing Category #{n}" } }
|
name { sequence(:name) { |n| "Amazing Category #{n}" } }
|
||||||
user
|
user
|
||||||
end
|
end
|
||||||
|
|
||||||
|
25
spec/fixtures/emails/valid_incoming.eml
vendored
Normal file
25
spec/fixtures/emails/valid_incoming.eml
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
Return-Path: <jake@adventuretime.ooo>
|
||||||
|
Received: from iceking.adventuretime.ooo ([unix socket]) by iceking (Cyrus v2.2.13-Debian-2.2.13-19+squeeze3) with LMTPA; Thu, 13 Jun 2013 17:03:50 -0400
|
||||||
|
Received: from mail-ie0-x234.google.com (mail-ie0-x234.google.com [IPv6:2607:f8b0:4001:c03::234]) by iceking.adventuretime.ooo (8.14.3/8.14.3/Debian-9.4) with ESMTP id r5DL3nFJ016967 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=NOT) for <discourse-in@appmail.adventuretime.ooo>; Thu, 13 Jun 2013 17:03:50 -0400
|
||||||
|
Received: by mail-ie0-f180.google.com with SMTP id f4so21977375iea.25 for <discourse-in@appmail.adventuretime.ooo>; Thu, 13 Jun 2013 14:03:48 -0700
|
||||||
|
Received: by 10.0.0.1 with HTTP; Thu, 13 Jun 2013 14:03:48 -0700
|
||||||
|
Date: Thu, 13 Jun 2013 17:03:48 -0400
|
||||||
|
From: Jake the Dog <jake@adventuretime.ooo>
|
||||||
|
To: discourse-in@appmail.adventuretime.ooo
|
||||||
|
Message-ID: <CADkmRc+rNGAGGbV2iE5p918UVy4UyJqVcXRO2=otppgzduJSg@mail.gmail.com>
|
||||||
|
Subject: We should have a post-by-email-feature.
|
||||||
|
Mime-Version: 1.0
|
||||||
|
Content-Type: text/plain;
|
||||||
|
charset=ISO-8859-1
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
X-Sieve: CMU Sieve 2.2
|
||||||
|
X-Received: by 10.0.0.1 with SMTP id n7mr11234144ipb.85.1371157428600; Thu,
|
||||||
|
13 Jun 2013 14:03:48 -0700 (PDT)
|
||||||
|
X-Scanned-By: MIMEDefang 2.69 on IPv6:2001:470:1d:165::1
|
||||||
|
|
||||||
|
Hey folks,
|
||||||
|
|
||||||
|
I was thinking. Wouldn't it be great if we could post topics via email? Yes it would!
|
||||||
|
|
||||||
|
Jakie
|
||||||
|
|
Loading…
Reference in New Issue
Block a user