diff --git a/Gemfile b/Gemfile
index 9428ae0a7..5d32bfd68 100644
--- a/Gemfile
+++ b/Gemfile
@@ -29,6 +29,8 @@ gem 'fog', require: false
gem 'has_ip_address'
gem 'hiredis'
+gem 'email_reply_parser'
+
# note: for image_optim to correctly work you need
# sudo apt-get install -y advancecomp gifsicle jpegoptim libjpeg-progs optipng pngcrush
gem 'image_optim'
diff --git a/Gemfile.lock b/Gemfile.lock
index e6aba121f..eae4c8a27 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -165,6 +165,7 @@ GEM
diffy (2.1.4)
em-redis (0.3.0)
eventmachine
+ email_reply_parser (0.5.3)
ember-rails (0.10.0)
active_model_serializers
barber
@@ -490,6 +491,7 @@ DEPENDENCIES
discourse_emoji!
discourse_plugin!
em-redis
+ email_reply_parser
ember-rails
ember-source (= 1.0.0.rc5)
eventmachine
diff --git a/app/assets/javascripts/admin/templates/email_logs.js.handlebars b/app/assets/javascripts/admin/templates/email_logs.js.handlebars
index 5e5758055..016211f9f 100644
--- a/app/assets/javascripts/admin/templates/email_logs.js.handlebars
+++ b/app/assets/javascripts/admin/templates/email_logs.js.handlebars
@@ -4,6 +4,7 @@
{{i18n user.title}} |
{{i18n admin.email.to_address}} |
{{i18n admin.email.email_type}} |
+ {{i18n admin.email.reply_key}} |
{{#if model.length}}
@@ -20,6 +21,7 @@
{{to_address}} |
{{email_type}} |
+ {{reply_key}} |
{{/collection}}
{{/group}}
{{/if}}
diff --git a/app/mailers/invite_mailer.rb b/app/mailers/invite_mailer.rb
index ac6336fe8..5d33b96b0 100644
--- a/app/mailers/invite_mailer.rb
+++ b/app/mailers/invite_mailer.rb
@@ -1,21 +1,18 @@
-require_dependency 'email/builder'
+require_dependency 'email/message_builder'
class InviteMailer < ActionMailer::Base
- default charset: 'UTF-8'
- include Email::Builder
+ include Email::BuildEmailHelper
def send_invite(invite)
-
# Find the first topic they were invited to
first_topic = invite.topics.order(:created_at).first
# If they were invited to a topic
- build_email invite.email,
- 'invite_mailer',
- invitee_name: invite.invited_by.username,
- invite_link: "#{Discourse.base_url}/invites/#{invite.invite_key}",
- topic_title: first_topic.try(:title)
-
+ build_email(invite.email,
+ template: 'invite_mailer',
+ invitee_name: invite.invited_by.username,
+ invite_link: "#{Discourse.base_url}/invites/#{invite.invite_key}",
+ topic_title: first_topic.try(:title))
end
end
diff --git a/app/mailers/test_mailer.rb b/app/mailers/test_mailer.rb
index 2a7f2a871..1b16c4dc1 100644
--- a/app/mailers/test_mailer.rb
+++ b/app/mailers/test_mailer.rb
@@ -1,11 +1,9 @@
-require_dependency 'email/builder'
+require_dependency 'email/message_builder'
class TestMailer < ActionMailer::Base
- default charset: 'UTF-8'
- include Email::Builder
+ include Email::BuildEmailHelper
def send_test(to_address)
- build_email to_address, 'test_mailer'
+ build_email(to_address, template: 'test_mailer')
end
-
end
diff --git a/app/mailers/user_notifications.rb b/app/mailers/user_notifications.rb
index e347e8730..1d36c0a81 100644
--- a/app/mailers/user_notifications.rb
+++ b/app/mailers/user_notifications.rb
@@ -1,44 +1,44 @@
require_dependency 'markdown_linker'
-require_dependency 'email/builder'
+require_dependency 'email/message_builder'
class UserNotifications < ActionMailer::Base
default charset: 'UTF-8'
- include Email::Builder
+ include Email::BuildEmailHelper
def signup(user, opts={})
- build_email(user.email, "user_notifications.signup", email_token: opts[:email_token])
+ build_email(user.email,
+ template: "user_notifications.signup",
+ email_token: opts[:email_token])
end
def signup_after_approval(user, opts={})
- build_email(
- user.email,
- 'user_notifications.signup_after_approval',
- email_token: opts[:email_token],
- new_user_tips: SiteContent.content_for(:usage_tips)
- )
+ build_email(user.email,
+ template: 'user_notifications.signup_after_approval',
+ email_token: opts[:email_token],
+ new_user_tips: SiteContent.content_for(:usage_tips))
end
def authorize_email(user, opts={})
- build_email(user.email, "user_notifications.authorize_email", email_token: opts[:email_token])
+ build_email(user.email, template: "user_notifications.authorize_email", email_token: opts[:email_token])
end
def forgot_password(user, opts={})
- build_email(user.email, "user_notifications.forgot_password", email_token: opts[:email_token])
+ build_email(user.email, template: "user_notifications.forgot_password", email_token: opts[:email_token])
end
def private_message(user, opts={})
post = opts[:post]
build_email user.email,
- "user_notifications.private_message",
- message: post.raw,
- url: post.url,
- subject_prefix: "[#{I18n.t('private_message_abbrev')}] #{post.post_number != 1 ? 're: ' : ''}",
- topic_title: post.topic.title,
- private_message_from: post.user.name,
- from: "#{I18n.t(:via, username: post.user.name, site_name: SiteSetting.title)} <#{SiteSetting.notification_email}>",
- add_unsubscribe_link: true
+ template: "user_notifications.private_message",
+ message: post.raw,
+ url: post.url,
+ subject_prefix: "[#{I18n.t('private_message_abbrev')}] #{post.post_number != 1 ? 're: ' : ''}",
+ topic_title: post.topic.title,
+ private_message_from: post.user.name,
+ from_alias: I18n.t(:via, username: post.user.name, site_name: SiteSetting.title),
+ add_unsubscribe_link: true
end
def digest(user, opts={})
@@ -57,11 +57,11 @@ class UserNotifications < ActionMailer::Base
# Don't send email unless there is content in it
if @new_topics.present?
- mail to: user.email,
- from: "#{I18n.t('user_notifications.digest.from', site_name: SiteSetting.title)} <#{SiteSetting.notification_email}>",
- subject: I18n.t('user_notifications.digest.subject_template',
- site_name: @site_name,
- date: I18n.l(Time.now, format: :short))
+ build_email user.email,
+ from_alias: I18n.t('user_notifications.digest.from', site_name: SiteSetting.title),
+ subject: I18n.t('user_notifications.digest.subject_template',
+ site_name: @site_name,
+ date: I18n.l(Time.now, format: :short))
end
end
@@ -80,16 +80,16 @@ class UserNotifications < ActionMailer::Base
message: @post.raw,
url: @post.url,
username: username,
- add_unsubscribe_link: true
+ add_unsubscribe_link: true,
+ template: "user_notifications.user_#{notification_type}"
}
# If we have a display name, change the from address
if username.present?
- aliased = I18n.t(:via, username: username, site_name: SiteSetting.title)
- email_opts[:from] = "#{aliased} <#{SiteSetting.notification_email}>"
+ email_opts[:from_alias] = I18n.t(:via, username: username, site_name: SiteSetting.title)
end
- email = build_email user.email, "user_notifications.user_#{notification_type}", email_opts
+ build_email(user.email, email_opts)
end
alias :user_invited_to_private_message :notification_template
diff --git a/app/models/email_log.rb b/app/models/email_log.rb
index 4c3b9de82..9e6e05613 100644
--- a/app/models/email_log.rb
+++ b/app/models/email_log.rb
@@ -3,6 +3,13 @@ class EmailLog < ActiveRecord::Base
validates_presence_of :email_type
validates_presence_of :to_address
+ before_create do
+ # We only generate a reply
+ if SiteSetting.reply_by_email_enabled?
+ self.reply_key = SecureRandom.hex(16)
+ end
+ end
+
after_create do
# Update last_emailed_at if the user_id is present
User.update_all("last_emailed_at = CURRENT_TIMESTAMP", id: user_id) if user_id.present?
diff --git a/app/models/site_setting.rb b/app/models/site_setting.rb
index c92029be6..c448e2cbc 100644
--- a/app/models/site_setting.rb
+++ b/app/models/site_setting.rb
@@ -188,6 +188,10 @@ class SiteSetting < ActiveRecord::Base
setting(:regular_requires_likes_given, 1)
setting(:regular_requires_topic_reply_count, 3)
+ # Reply by Email Settings
+ setting(:reply_by_email_enabled, false)
+ setting(:reply_by_email_address, nil)
+
# Entropy checks
setting(:title_min_entropy, 10)
setting(:body_min_entropy, 7)
diff --git a/app/serializers/email_log_serializer.rb b/app/serializers/email_log_serializer.rb
index 56ad183f0..0461d739c 100644
--- a/app/serializers/email_log_serializer.rb
+++ b/app/serializers/email_log_serializer.rb
@@ -1,6 +1,12 @@
class EmailLogSerializer < ApplicationSerializer
- attributes :id, :to_address, :email_type, :user_id, :created_at
+ attributes :id,
+ :reply_key,
+ :to_address,
+ :email_type,
+ :user_id,
+ :created_at
+
has_one :user, serializer: BasicUserSerializer, embed: :objects
end
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index cfe794c7d..5452ddb63 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -1086,6 +1086,7 @@ en:
html: "html"
text: "text"
last_seen_user: "Last Seen User:"
+ reply_key: "Reply Key"
impersonate:
title: "Impersonate User"
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 0918ca59c..274f17112 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -612,6 +612,9 @@ en:
newuser_spam_host_threshold: "How many times a new user can post a link to the same host within their `newuser_spam_host_posts` posts before being considered spam."
staff_like_weight: "Extra weighting factor given to likes when performed by staff."
+ reply_by_email_enabled: "Whether this forum supports reply by email"
+ reply_by_email_address: "Template for reply by email address in form, for example: %{reply_key}@reply.myforum.com"
+
notification_types:
mentioned: "%{display_username} mentioned you in %{link}"
liked: "%{display_username} liked your post in %{link}"
diff --git a/db/migrate/20130610201033_add_reply_key_to_email_logs.rb b/db/migrate/20130610201033_add_reply_key_to_email_logs.rb
new file mode 100644
index 000000000..929510107
--- /dev/null
+++ b/db/migrate/20130610201033_add_reply_key_to_email_logs.rb
@@ -0,0 +1,6 @@
+class AddReplyKeyToEmailLogs < ActiveRecord::Migration
+ def change
+ add_column :email_logs, :reply_key, :string, limit: 32
+ add_index :email_logs, :reply_key
+ end
+end
diff --git a/lib/email.rb b/lib/email.rb
index bab4a99c7..0075b2a90 100644
--- a/lib/email.rb
+++ b/lib/email.rb
@@ -1,5 +1,5 @@
require 'mail'
-require_dependency 'email/builder'
+require_dependency 'email/message_builder'
require_dependency 'email/renderer'
require_dependency 'email/sender'
require_dependency 'email/styles'
diff --git a/lib/email/builder.rb b/lib/email/builder.rb
deleted file mode 100644
index d68b73742..000000000
--- a/lib/email/builder.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# Help us build an email
-module Email
-
- module Builder
-
- def build_email(to, email_key, params={})
- params[:site_name] = SiteSetting.title
- params[:base_url] = Discourse.base_url
- params[:user_preferences_url] = "#{Discourse.base_url}/user_preferences"
-
- body = I18n.t("#{email_key}.text_body_template", params)
-
- # Are we appending an unsubscribe link?
- if params[:add_unsubscribe_link]
- body << "\n"
- body << I18n.t("unsubscribe_link", params)
- headers 'List-Unsubscribe' => "<#{params[:user_preferences_url]}>"
- end
-
- mail_args = {
- to: to,
- subject: I18n.t("#{email_key}.subject_template", params),
- body: body
- }
- mail_args[:from] = params[:from] || SiteSetting.notification_email
- mail_args[:charset] = 'UTF-8'
- mail(mail_args)
- end
-
- end
-
-end
diff --git a/lib/email/incoming_message.rb b/lib/email/incoming_message.rb
new file mode 100644
index 000000000..b3dfc965f
--- /dev/null
+++ b/lib/email/incoming_message.rb
@@ -0,0 +1,19 @@
+module Email
+
+ class IncomingMessage
+
+ attr_reader :reply_key,
+ :body_plain
+
+ def initialize(reply_key, body)
+ @reply_key = reply_key
+ @body = body
+ end
+
+ def reply
+ @reply ||= EmailReplyParser.read(@body).visible_text
+ end
+
+ end
+
+end
\ No newline at end of file
diff --git a/lib/email/message_builder.rb b/lib/email/message_builder.rb
new file mode 100644
index 000000000..b74499d29
--- /dev/null
+++ b/lib/email/message_builder.rb
@@ -0,0 +1,68 @@
+# Builds a Mail::Mesage we can use for sending. Optionally supports using a template
+# for the body and subject
+module Email
+
+ module BuildEmailHelper
+ def build_email(*builder_args)
+ builder = Email::MessageBuilder.new(*builder_args)
+ headers(builder.header_args) if builder.header_args.present?
+ mail(builder.build_args)
+ end
+ end
+
+ class MessageBuilder
+
+ def initialize(to, opts=nil)
+ @to = to
+ @opts = opts || {}
+ end
+
+ def subject
+ subject = @opts[:subject]
+ subject = I18n.t("#{@opts[:template]}.subject_template", template_args) if @opts[:template]
+ subject
+ end
+
+ def body
+ body = @opts[:body]
+ body = I18n.t("#{@opts[:template]}.text_body_template", template_args) if @opts[:template]
+
+ if @opts[:add_unsubscribe_link]
+ body << "\n"
+ body << I18n.t('unsubscribe_link', template_args)
+ end
+
+ body
+ end
+
+ def template_args
+ @template_args ||= { site_name: SiteSetting.title,
+ base_url: Discourse.base_url,
+ user_preferences_url: "#{Discourse.base_url}/user_preferences" }.merge!(@opts)
+ end
+
+ def build_args
+ mail_args = { to: @to,
+ subject: subject,
+ body: body,
+ charset: 'UTF-8' }
+
+ mail_args[:from] = @opts[:from] || SiteSetting.notification_email
+
+ if @opts[:from_alias]
+ mail_args[:from] = "#{@opts[:from_alias]} <#{mail_args[:from]}>"
+ end
+ mail_args
+ end
+
+ def header_args
+ result = {}
+ if @opts[:add_unsubscribe_link]
+ result['List-Unsubscribe'] = "<#{template_args[:user_preferences_url]}>" if @opts[:add_unsubscribe_link]
+ end
+ result
+ end
+
+ end
+
+end
diff --git a/lib/email/receiver.rb b/lib/email/receiver.rb
new file mode 100644
index 000000000..bb1c6781e
--- /dev/null
+++ b/lib/email/receiver.rb
@@ -0,0 +1,30 @@
+#
+# Handles an incoming message
+#
+require_dependency 'email/incoming_message'
+
+module Email
+ class Receiver
+
+ def self.results
+ @results ||= Enum.new(:unprocessable)
+ end
+
+ def initialize(incoming_message)
+ @incoming_message = incoming_message
+ end
+
+ def process
+
+ if @incoming_message.blank? || @incoming_message.reply_key.blank?
+ return Email::Receiver.results[:unprocessable]
+ end
+
+ log = EmailLog.where(reply_key: @incoming_message.reply_key).first
+ return Email::Receiver.results[:unprocessable] if log.blank?
+
+ nil
+ end
+
+ end
+end
diff --git a/lib/jobs/user_email.rb b/lib/jobs/user_email.rb
index 47f7430b0..19468c20d 100644
--- a/lib/jobs/user_email.rb
+++ b/lib/jobs/user_email.rb
@@ -47,17 +47,7 @@ module Jobs
return if notification.read?
end
- # Check that the post has not been deleted or read
- if email_args[:post]
-
- post = email_args[:post]
-
- # Don't email about deleted topics or user deleted posts
- return if post.topic.blank? || post.user_deleted?
-
- # Don't send the email if the user has read the post
- return if PostTiming.where(topic_id: post.topic_id, post_number: post.post_number, user_id: user.id).present?
- end
+ return if skip_email_for_post(email_args[:post], user)
# Make sure that mailer exists
raise Discourse::InvalidParameters.new(:type) unless UserNotifications.respond_to?(args[:type])
@@ -70,7 +60,16 @@ module Jobs
end
Email::Sender.new(message, args[:type], user).send
+ end
+ private
+
+ # If this email has a related post, don't send an email if it's been deleted or seen recently.
+ def skip_email_for_post(post, user)
+ post &&
+ (post.topic.blank? ||
+ post.user_deleted? ||
+ PostTiming.where(topic_id: post.topic_id, post_number: post.post_number, user_id: user.id).present?)
end
end
diff --git a/spec/components/email/incoming_email_spec.rb b/spec/components/email/incoming_email_spec.rb
new file mode 100644
index 000000000..e128813aa
--- /dev/null
+++ b/spec/components/email/incoming_email_spec.rb
@@ -0,0 +1,16 @@
+require 'spec_helper'
+require 'email/receiver'
+
+describe Email::IncomingMessage do
+
+ let(:message) { Email::IncomingMessage.new("asdf", "hello\n\n> how are you?") }
+
+ it "returns the reply_key" do
+ expect(message.reply_key).to eq("asdf")
+ end
+
+ it "extracts the reply" do
+ expect(message.reply).to eq("hello")
+ end
+
+end
diff --git a/spec/components/email/message_builder_spec.rb b/spec/components/email/message_builder_spec.rb
new file mode 100644
index 000000000..973cca81e
--- /dev/null
+++ b/spec/components/email/message_builder_spec.rb
@@ -0,0 +1,121 @@
+require 'spec_helper'
+require 'email/message_builder'
+
+describe Email::MessageBuilder do
+
+ let(:to_address) { "jake@adventuretime.ooo" }
+ let(:subject) { "Tree Trunks has made some apple pie!" }
+ let(:body) { "oh my glob Jake, Tree Trunks just made the tastiest apple pie ever!"}
+ let(:builder) { Email::MessageBuilder.new(to_address, subject: subject, body: body) }
+ let(:build_args) { builder.build_args }
+
+ it "has the correct to address" do
+ expect(build_args[:to]).to eq(to_address)
+ end
+
+ it "has the subject" do
+ expect(builder.subject).to eq(subject)
+ end
+
+ it "has the body" do
+ expect(builder.body).to eq(body)
+ end
+
+ it "has a utf-8 charset" do
+ expect(builder.build_args[:charset]).to eq("UTF-8")
+ end
+
+ context "unsubscribe link" do
+
+ context "with add_unsubscribe_link false" do
+ it "has no unsubscribe header by default" do
+ expect(builder.header_args['List-Unsubscribe']).to be_blank
+ end
+
+ it "doesn't have the user preferences url in the body" do
+ expect(builder.body).not_to match(builder.template_args[:user_preferences_url])
+ end
+
+ end
+
+ context "with add_unsubscribe_link true" do
+
+ let(:message_with_unsubscribe) { Email::MessageBuilder.new(to_address,
+ body: 'hello world',
+ add_unsubscribe_link: true) }
+
+ it "has an List-Unsubscribe header" do
+ expect(message_with_unsubscribe.header_args['List-Unsubscribe']).to be_present
+ end
+
+ it "has the user preferences url in the body" do
+ expect(message_with_unsubscribe.body).to match(builder.template_args[:user_preferences_url])
+ end
+
+ end
+
+ end
+
+ context "template_args" do
+ let(:template_args) { builder.template_args }
+
+ it "has the site name" do
+ expect(template_args[:site_name]).to eq(SiteSetting.title)
+ end
+
+ it "has the base url" do
+ expect(template_args[:base_url]).to eq(Discourse.base_url)
+ end
+
+ it "has the user_preferences_url" do
+ expect(template_args[:user_preferences_url]).to eq("#{Discourse.base_url}/user_preferences")
+ end
+ end
+
+ context "subject_template" do
+
+ let(:templated_builder) { Email::MessageBuilder.new(to_address, template: 'mystery') }
+ let(:rendered_template) { "rendered template" }
+
+ it "has the body rendered from a template" do
+ I18n.expects(:t).with("mystery.text_body_template", templated_builder.template_args).returns(rendered_template)
+ expect(templated_builder.body).to eq(rendered_template)
+ end
+
+ it "has the subject rendered from a template" do
+ I18n.expects(:t).with("mystery.subject_template", templated_builder.template_args).returns(rendered_template)
+ expect(templated_builder.subject).to eq(rendered_template)
+ end
+
+ end
+
+ context "from field" do
+
+ it "has the default from" do
+ expect(build_args[:from]).to eq(SiteSetting.notification_email)
+ end
+
+ let(:finn_email) { 'finn@adventuretime.ooo' }
+ let(:custom_from) { Email::MessageBuilder.new(to_address, from: finn_email).build_args }
+
+ it "allows us to override from" do
+ expect(custom_from[:from]).to eq(finn_email)
+ end
+
+ let(:aliased_from) { Email::MessageBuilder.new(to_address, from_alias: "Finn the Dog") }
+
+ it "allows us to alias the from address" do
+ expect(aliased_from.build_args[:from]).to eq("Finn the Dog <#{SiteSetting.notification_email}>")
+ end
+
+ let(:custom_aliased_from) { Email::MessageBuilder.new(to_address,
+ from_alias: "Finn the Dog",
+ from: finn_email) }
+
+ it "allows us to alias a custom from address" do
+ expect(custom_aliased_from.build_args[:from]).to eq("Finn the Dog <#{finn_email}>")
+ end
+
+ end
+
+end
diff --git a/spec/components/email/receiver_spec.rb b/spec/components/email/receiver_spec.rb
new file mode 100644
index 000000000..19525ab92
--- /dev/null
+++ b/spec/components/email/receiver_spec.rb
@@ -0,0 +1,19 @@
+require 'spec_helper'
+require 'email/receiver'
+
+describe Email::Receiver do
+
+
+ describe 'invalid key' do
+ let(:incoming) { Email::IncomingMessage.new('asdf', 'hello') }
+
+ it "returns unprocessable for nil message" do
+ expect(Email::Receiver.new(nil).process).to eq(Email::Receiver.results[:unprocessable])
+ end
+
+ it "returns unprocessable for a made up key" do
+ expect(Email::Receiver.new(incoming).process).to eq(Email::Receiver.results[:unprocessable])
+ end
+ end
+
+end
diff --git a/spec/components/email/email_sender_spec.rb b/spec/components/email/sender_spec.rb
similarity index 100%
rename from spec/components/email/email_sender_spec.rb
rename to spec/components/email/sender_spec.rb
diff --git a/spec/components/email/email_styles_spec.rb b/spec/components/email/styles_spec.rb
similarity index 100%
rename from spec/components/email/email_styles_spec.rb
rename to spec/components/email/styles_spec.rb
diff --git a/spec/mailers/user_notifications_spec.rb b/spec/mailers/user_notifications_spec.rb
index 26419e35b..6093eb7fa 100644
--- a/spec/mailers/user_notifications_spec.rb
+++ b/spec/mailers/user_notifications_spec.rb
@@ -22,7 +22,7 @@ describe UserNotifications do
its(:body) { should be_present }
end
- describe '.daily_digest' do
+ describe '.digest' do
subject { UserNotifications.digest(user) }
context "without new topics" do
diff --git a/spec/models/email_log_spec.rb b/spec/models/email_log_spec.rb
index 3e362ff84..7267f8eca 100644
--- a/spec/models/email_log_spec.rb
+++ b/spec/models/email_log_spec.rb
@@ -8,15 +8,51 @@ describe EmailLog do
it { should validate_presence_of :email_type }
- context 'after_create with user' do
+ context 'after_create' do
- let(:user) { Fabricate(:user) }
+ context "reply_key" do
- it 'updates the last_emailed_at value for the user' do
- lambda {
- user.email_logs.create(email_type: 'blah', to_address: user.email)
- user.reload
- }.should change(user, :last_emailed_at)
+ context "with reply by email enabled" do
+ before do
+ SiteSetting.expects(:reply_by_email_enabled).returns(true)
+ end
+
+ context 'generates a reply key' do
+ let(:reply_key) { Fabricate(:email_log).reply_key }
+
+ it "has a reply key" do
+ expect(reply_key).to be_present
+ expect(reply_key.size).to eq(32)
+ end
+ end
+ end
+
+ context "with reply by email disabled" do
+ before do
+ SiteSetting.expects(:reply_by_email_enabled).returns(false)
+ end
+
+ context 'generates a reply key' do
+ let(:reply_key) { Fabricate(:email_log).reply_key }
+
+ it "has no reply key" do
+ expect(reply_key).to be_blank
+ end
+ end
+ end
+
+ end
+
+
+ context 'with user' do
+ let(:user) { Fabricate(:user) }
+
+ it 'updates the last_emailed_at value for the user' do
+ lambda {
+ user.email_logs.create(email_type: 'blah', to_address: user.email)
+ user.reload
+ }.should change(user, :last_emailed_at)
+ end
end
end