FEATURE: better email in support

FEATURE: new incoming_email model
FEATURE: infinite scrolling in emails admin
FEATURE: new 'emails:import' rake task
This commit is contained in:
Régis Hanol 2016-01-19 00:57:55 +01:00
parent d0bcea3411
commit 3083657358
119 changed files with 1560 additions and 4408 deletions

View file

@ -1,3 +0,0 @@
import AdminEmailSkippedController from "admin/controllers/admin-email-skipped";
export default AdminEmailSkippedController.extend();

View file

@ -0,0 +1,11 @@
import IncomingEmail from 'admin/models/incoming-email';
export default Ember.Controller.extend({
loadMore() {
return IncomingEmail.findAll(this.get("filter"), this.get("model.length"))
.then(incoming => {
if (incoming.length < 50) { this.get("model").set("allLoaded", true); }
this.get("model").addObjects(incoming);
});
}
});

View file

@ -0,0 +1,11 @@
import EmailLog from 'admin/models/email-log';
export default Ember.Controller.extend({
loadMore() {
return EmailLog.findAll(this.get("filter"), this.get("model.length"))
.then(logs => {
if (logs.length < 50) { this.get("model").set("allLoaded", true); }
this.get("model").addObjects(logs);
});
}
});

View file

@ -0,0 +1,9 @@
import AdminEmailIncomingsController from 'admin/controllers/admin-email-incomings';
import debounce from 'discourse/lib/debounce';
import IncomingEmail from 'admin/models/incoming-email';
export default AdminEmailIncomingsController.extend({
filterIncomingEmails: debounce(function() {
IncomingEmail.findAll(this.get("filter")).then(incomings => this.set("model", incomings));
}, 250).observes("filter.{from,to,subject}")
});

View file

@ -0,0 +1,9 @@
import AdminEmailIncomingsController from 'admin/controllers/admin-email-incomings';
import debounce from 'discourse/lib/debounce';
import IncomingEmail from 'admin/models/incoming-email';
export default AdminEmailIncomingsController.extend({
filterIncomingEmails: debounce(function() {
IncomingEmail.findAll(this.get("filter")).then(incomings => this.set("model", incomings));
}, 250).observes("filter.{from,to,subject,error}")
});

View file

@ -1,12 +1,9 @@
import AdminEmailLogsController from 'admin/controllers/admin-email-logs';
import debounce from 'discourse/lib/debounce';
import EmailLog from 'admin/models/email-log';
export default Ember.Controller.extend({
export default AdminEmailLogsController.extend({
filterEmailLogs: debounce(function() {
var self = this;
EmailLog.findAll(this.get("filter")).then(function(logs) {
self.set("model", logs);
});
}, 250).observes("filter.user", "filter.address", "filter.type", "filter.reply_key")
EmailLog.findAll(this.get("filter")).then(logs => this.set("model", logs));
}, 250).observes("filter.{user,address,type,reply_key}")
});

View file

@ -1,8 +1,9 @@
import AdminEmailLogsController from 'admin/controllers/admin-email-logs';
import debounce from 'discourse/lib/debounce';
import EmailLog from 'admin/models/email-log';
export default Ember.Controller.extend({
export default AdminEmailLogsController.extend({
filterEmailLogs: debounce(function() {
const EmailLog = require('admin/models/email-log').default;
EmailLog.findAll(this.get("filter")).then(logs => this.set("model", logs));
}, 250).observes("filter.user", "filter.address", "filter.type", "filter.skipped_reason")
}, 250).observes("filter.{user,address,type,skipped_reason}")
});

View file

@ -4,7 +4,7 @@ const EmailLog = Discourse.Model.extend({});
EmailLog.reopenClass({
create: function(attrs) {
create(attrs) {
attrs = attrs || {};
if (attrs.user) {
@ -14,16 +14,15 @@ EmailLog.reopenClass({
return this._super(attrs);
},
findAll: function(filter) {
findAll(filter, offset) {
filter = filter || {};
var status = filter.status || "all";
offset = offset || 0;
const status = filter.status || "sent";
filter = _.omit(filter, "status");
return Discourse.ajax("/admin/email/" + status + ".json", { data: filter }).then(function(logs) {
return _.map(logs, function (log) {
return EmailLog.create(log);
});
});
return Discourse.ajax(`/admin/email/${status}.json?offset=${offset}`, { data: filter })
.then(logs => _.map(logs, log => EmailLog.create(log)));
}
});

View file

@ -0,0 +1,29 @@
import AdminUser from 'admin/models/admin-user';
const IncomingEmail = Discourse.Model.extend({});
IncomingEmail.reopenClass({
create(attrs) {
attrs = attrs || {};
if (attrs.user) {
attrs.user = AdminUser.create(attrs.user);
}
return this._super(attrs);
},
findAll(filter, offset) {
filter = filter || {};
offset = offset || 0;
const status = filter.status || "received";
filter = _.omit(filter, "status");
return Discourse.ajax(`/admin/email/${status}.json?offset=${offset}`, { data: filter })
.then(incomings => _.map(incomings, incoming => IncomingEmail.create(incoming)));
}
});
export default IncomingEmail;

View file

@ -1,2 +0,0 @@
import AdminEmailLogs from 'admin/routes/admin-email-logs';
export default AdminEmailLogs.extend({ status: "all" });

View file

@ -0,0 +1,14 @@
import IncomingEmail from 'admin/models/incoming-email';
export default Discourse.Route.extend({
model() {
return IncomingEmail.findAll({ status: this.get("status") });
},
setupController(controller, model) {
controller.set("model", model);
controller.set("filter", { status: this.get("status") });
}
});

View file

@ -1,11 +1,11 @@
import EmailSettings from 'admin/models/email-settings';
export default Discourse.Route.extend({
model: function() {
model() {
return EmailSettings.find();
},
renderTemplate: function() {
renderTemplate() {
this.render('admin/templates/email_index', { into: 'adminEmail' });
}
});

View file

@ -1,27 +1,14 @@
import EmailLog from 'admin/models/email-log';
/**
Handles routes related to viewing email logs.
@class AdminEmailSentRoute
@extends Discourse.Route
@namespace Discourse
@module Discourse
**/
export default Discourse.Route.extend({
model: function() {
model() {
return EmailLog.findAll({ status: this.get("status") });
},
setupController: function(controller, model) {
setupController(controller, model) {
controller.set("model", model);
// resets the filters
controller.set("filter", { status: this.get("status") });
},
renderTemplate: function() {
this.render("admin/templates/email_" + this.get("status"), { into: "adminEmail" });
}
});

View file

@ -0,0 +1,2 @@
import AdminEmailIncomings from 'admin/routes/admin-email-incomings';
export default AdminEmailIncomings.extend({ status: "received" });

View file

@ -0,0 +1,2 @@
import AdminEmailIncomings from 'admin/routes/admin-email-incomings';
export default AdminEmailIncomings.extend({ status: "rejected" });

View file

@ -8,9 +8,10 @@ export default {
});
this.resource('adminEmail', { path: '/email'}, function() {
this.route('all');
this.route('sent');
this.route('skipped');
this.route('received');
this.route('rejected');
this.route('previewDigest', { path: '/preview-digest' });
});

View file

@ -0,0 +1,55 @@
<table class='table email-list'>
<thead>
<tr>
<th>{{i18n 'admin.email.time'}}</th>
<th>{{i18n 'admin.email.incoming_emails.from_address'}}</th>
<th>{{i18n 'admin.email.incoming_emails.to_addresses'}}</th>
<th>{{i18n 'admin.email.incoming_emails.subject'}}</th>
</tr>
</thead>
<tr class="filters">
<td>{{i18n 'admin.email.logs.filters.title'}}</td>
<td>{{text-field value=filter.from placeholderKey="admin.email.incoming_emails.filters.from_placeholder"}}</td>
<td>{{text-field value=filter.to placeholderKey="admin.email.incoming_emails.filters.to_placeholder"}}</td>
<td>{{text-field value=filter.subject placeholderKey="admin.email.incoming_emails.filters.subject_placeholder"}}</td>
</tr>
{{#each email in model}}
<tr>
<td class="time">{{format-date email.created_at}}</td>
<td class="username">
<div>
{{#if email.user}}
{{#link-to 'adminUser' email.user}}
{{avatar email.user imageSize="tiny"}}
{{email.from_address}}
{{/link-to}}
{{else}}
&mdash;
{{/if}}
</div>
</td>
<td class="addresses">
{{#each to in email.to_addresses}}
<p><a href="mailto:{{unbound to}}" title="TO">{{unbound to}}</a></p>
{{/each}}
{{#each cc in email.cc_addresses}}
<p><a href="mailto:{{unbound cc}}" title="CC">{{unbound cc}}</a></p>
{{/each}}
</td>
<td>
{{#if email.post_url}}
<a href="{{email.post_url}}">{{email.subject}}</a>
{{else}}
{{email.subject}}
{{/if}}
</td>
</tr>
{{else}}
<tr><td colspan="4">{{i18n 'admin.email.incoming_emails.none'}}</td></tr>
{{/each}}
</table>
{{conditional-loading-spinner condition=view.loading}}

View file

@ -0,0 +1,52 @@
<table class='table email-list'>
<thead>
<tr>
<th>{{i18n 'admin.email.time'}}</th>
<th>{{i18n 'admin.email.incoming_emails.from_address'}}</th>
<th>{{i18n 'admin.email.incoming_emails.to_addresses'}}</th>
<th>{{i18n 'admin.email.incoming_emails.subject'}}</th>
<th>{{i18n 'admin.email.incoming_emails.error'}}</th>
</tr>
</thead>
<tr class="filters">
<td>{{i18n 'admin.email.logs.filters.title'}}</td>
<td>{{text-field value=filter.from placeholderKey="admin.email.incoming_emails.filters.from_placeholder"}}</td>
<td>{{text-field value=filter.to placeholderKey="admin.email.incoming_emails.filters.to_placeholder"}}</td>
<td>{{text-field value=filter.subject placeholderKey="admin.email.incoming_emails.filters.subject_placeholder"}}</td>
<td>{{text-field value=filter.error placeholderKey="admin.email.incoming_emails.filters.error_placeholder"}}</td>
</tr>
{{#each email in model}}
<tr>
<td class="time">{{format-date email.created_at}}</td>
<td class="username">
<div>
{{#if email.user}}
{{#link-to 'adminUser' email.user}}
{{avatar email.user imageSize="tiny"}}
{{email.from_address}}
{{/link-to}}
{{else}}
&mdash;
{{/if}}
</div>
</td>
<td class="addresses">
{{#each to in email.to_addresses}}
<p><a href="mailto:{{unbound to}}" title="TO">{{unbound to}}</a></p>
{{/each}}
{{#each cc in email.cc_addresses}}
<p><a href="mailto:{{unbound cc}}" title="CC">{{unbound cc}}</a></p>
{{/each}}
</td>
<td>{{email.subject}}</td>
<td class="error">{{email.error}}</td>
</tr>
{{else}}
<tr><td colspan="5">{{i18n 'admin.email.incoming_emails.none'}}</td></tr>
{{/each}}
</table>
{{conditional-loading-spinner condition=view.loading}}

View file

@ -1,4 +1,4 @@
<table class='table'>
<table class='table email-list'>
<thead>
<tr>
<th>{{i18n 'admin.email.sent_at'}}</th>
@ -37,3 +37,5 @@
{{/each}}
</table>
{{conditional-loading-spinner condition=view.loading}}

View file

@ -1,4 +1,4 @@
<table class='table'>
<table class='table email-list'>
<thead>
<tr>
<th>{{i18n 'admin.email.time'}}</th>
@ -37,3 +37,5 @@
{{/each}}
</table>
{{conditional-loading-spinner condition=view.loading}}

View file

@ -1,10 +1,11 @@
{{#admin-nav}}
{{nav-item route='adminEmail.index' label='admin.email.settings'}}
{{nav-item route='adminEmail.all' label='admin.email.all'}}
{{nav-item route='adminEmail.previewDigest' label='admin.email.preview_digest'}}
{{nav-item route='adminCustomizeEmailTemplates' label='admin.email.templates'}}
{{nav-item route='adminEmail.sent' label='admin.email.sent'}}
{{nav-item route='adminEmail.skipped' label='admin.email.skipped'}}
{{nav-item route='adminEmail.previewDigest' label='admin.email.preview_digest'}}
{{nav-item route='adminCustomizeEmailTemplates' label='admin.customize.email_templates.title'}}
{{nav-item route='adminEmail.received' label='admin.email.received'}}
{{nav-item route='adminEmail.rejected' label='admin.email.rejected'}}
{{/admin-nav}}
<div class="admin-container">

View file

@ -1,39 +0,0 @@
<table class='table'>
<thead>
<tr>
<th>{{i18n 'admin.email.time'}}</th>
<th>{{i18n 'admin.email.user'}}</th>
<th>{{i18n 'admin.email.to_address'}}</th>
<th>{{i18n 'admin.email.email_type'}}</th>
<th>{{i18n 'admin.email.skipped_reason'}}</th>
</tr>
</thead>
<tr class="filters">
<td>{{i18n 'admin.email.logs.filters.title'}}</td>
<td>{{text-field value=filter.user placeholderKey="admin.email.logs.filters.user_placeholder"}}</td>
<td>{{text-field value=filter.address placeholderKey="admin.email.logs.filters.address_placeholder"}}</td>
<td>{{text-field value=filter.type placeholderKey="admin.email.logs.filters.type_placeholder"}}</td>
<td>{{text-field value=filter.skipped_reason placeholderKey="admin.email.logs.filters.skipped_reason_placeholder"}}</td>
</tr>
{{#each l in model}}
<tr>
<td>{{format-date l.created_at}}</td>
<td>
{{#if l.user}}
{{#link-to 'adminUser' l.user}}{{avatar l.user imageSize="tiny"}}{{/link-to}}
{{#link-to 'adminUser' l.user}}{{l.user.username}}{{/link-to}}
{{else}}
&mdash;
{{/if}}
</td>
<td><a href='mailto:{{unbound l.to_address}}'>{{l.to_address}}</a></td>
<td>{{l.email_type}}</td>
<td>{{l.skipped_reason}}</td>
</tr>
{{else}}
<tr><td colspan="5">{{i18n 'admin.email.logs.none'}}</td></tr>
{{/each}}
</table>

View file

@ -0,0 +1,14 @@
import LoadMore from "discourse/mixins/load-more";
export default Ember.View.extend(LoadMore, {
loading: false,
eyelineSelector: ".email-list tr",
actions: {
loadMore() {
if (this.get("loading") || this.get("model.allLoaded")) { return; }
this.set("loading", true);
return this.get("controller").loadMore().then(() => this.set("loading", false));
}
}
});

View file

@ -0,0 +1,14 @@
import LoadMore from "discourse/mixins/load-more";
export default Ember.View.extend(LoadMore, {
loading: false,
eyelineSelector: ".email-list tr",
actions: {
loadMore() {
if (this.get("loading") || this.get("model.allLoaded")) { return; }
this.set("loading", true);
return this.get("controller").loadMore().then(() => this.set("loading", false));
}
}
});

View file

@ -0,0 +1,5 @@
import AdminEmailIncomingsView from "admin/views/admin-email-incomings";
export default AdminEmailIncomingsView.extend({
templateName: "admin/templates/email-received"
});

View file

@ -0,0 +1,5 @@
import AdminEmailIncomingsView from "admin/views/admin-email-incomings";
export default AdminEmailIncomingsView.extend({
templateName: "admin/templates/email-rejected"
});

View file

@ -0,0 +1,5 @@
import AdminEmailLogsView from "admin/views/admin-email-logs";
export default AdminEmailLogsView.extend({
templateName: "admin/templates/email-sent"
});

View file

@ -0,0 +1,5 @@
import AdminEmailLogsView from "admin/views/admin-email-logs";
export default AdminEmailLogsView.extend({
templateName: "admin/templates/email-skipped"
});

View file

@ -1769,6 +1769,30 @@ table#user-badges {
}
}
// Emails
.email-list {
.filters input {
width: 100%;
}
.time {
width: 50px;
}
.username div {
max-width: 180px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.addresses p {
margin: 2px 0;
max-width: 200px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
// Mobile specific styles
// Mobile view text-inputs need some padding
.mobile-view .admin-contents {

View file

@ -17,11 +17,6 @@ class Admin::EmailController < Admin::AdminController
end
end
def all
email_logs = filter_email_logs(EmailLog.all, params)
render_serialized(email_logs, EmailLogSerializer)
end
def sent
email_logs = filter_email_logs(EmailLog.sent, params)
render_serialized(email_logs, EmailLogSerializer)
@ -32,6 +27,16 @@ class Admin::EmailController < Admin::AdminController
render_serialized(email_logs, EmailLogSerializer)
end
def received
incoming_emails = filter_incoming_emails(IncomingEmail, params)
render_serialized(incoming_emails, IncomingEmailSerializer)
end
def rejected
incoming_emails = filter_incoming_emails(IncomingEmail.errored, params)
render_serialized(incoming_emails, IncomingEmailSerializer)
end
def preview_digest
params.require(:last_seen_at)
params.require(:username)
@ -49,13 +54,33 @@ class Admin::EmailController < Admin::AdminController
private
def filter_email_logs(email_logs, params)
email_logs = email_logs.limit(50).includes(:user).order("email_logs.created_at desc").references(:user)
email_logs = email_logs.where("users.username LIKE ?", "%#{params[:user]}%") if params[:user].present?
email_logs = email_logs.where("email_logs.to_address LIKE ?", "%#{params[:address]}%") if params[:address].present?
email_logs = email_logs.where("email_logs.email_type LIKE ?", "%#{params[:type]}%") if params[:type].present?
email_logs = email_logs.where("email_logs.reply_key LIKE ?", "%#{params[:reply_key]}%") if params[:reply_key].present?
email_logs = email_logs.where("email_logs.skipped_reason LIKE ?", "%#{params[:skipped_reason]}%") if params[:skipped_reason].present?
email_logs.to_a
email_logs = email_logs.includes(:user)
.references(:user)
.order(created_at: :desc)
.offset(params[:offset] || 0)
.limit(50)
email_logs = email_logs.where("users.username ILIKE ?", "%#{params[:user]}%") if params[:user].present?
email_logs = email_logs.where("email_logs.to_address ILIKE ?", "%#{params[:address]}%") if params[:address].present?
email_logs = email_logs.where("email_logs.email_type ILIKE ?", "%#{params[:type]}%") if params[:type].present?
email_logs = email_logs.where("email_logs.reply_key ILIKE ?", "%#{params[:reply_key]}%") if params[:reply_key].present?
email_logs = email_logs.where("email_logs.skipped_reason ILIKE ?", "%#{params[:skipped_reason]}%") if params[:skipped_reason].present?
email_logs
end
def filter_incoming_emails(incoming_emails, params)
incoming_emails = incoming_emails.includes(:user, { post: :topic })
.order(created_at: :desc)
.offset(params[:offset] || 0)
.limit(50)
incoming_emails = incoming_emails.where("from_address ILIKE ?", "%#{params[:from]}%") if params[:from].present?
incoming_emails = incoming_emails.where("to_addresses ILIKE ? OR cc_addresses ILIKE ?", "%#{params[:to]}%") if params[:to].present?
incoming_emails = incoming_emails.where("subject ILIKE ?", "%#{params[:subject]}%") if params[:subject].present?
incoming_emails = incoming_emails.where("error ILIKE ?", "%#{params[:error]}%") if params[:error].present?
incoming_emails
end
def delivery_settings

View file

@ -1,6 +1,3 @@
#
# Connects to a mailbox and checks for replies
#
require 'net/pop'
require_dependency 'email/receiver'
require_dependency 'email/sender'
@ -10,6 +7,7 @@ module Jobs
class PollMailbox < Jobs::Scheduled
every SiteSetting.pop3_polling_period_mins.minutes
sidekiq_options retry: false
include Email::BuildEmailHelper
def execute(args)
@ -17,53 +15,42 @@ module Jobs
poll_pop3 if SiteSetting.pop3_polling_enabled?
end
def handle_mail(mail)
def process_popmail(popmail)
begin
mail_string = mail.pop
mail_string = popmail.pop
Email::Receiver.new(mail_string).process
rescue => e
handle_failure(mail_string, e)
ensure
mail.delete
end
end
def handle_failure(mail_string, e)
Rails.logger.warn("Email can not be processed: #{e}\n\n#{mail_string}") if SiteSetting.log_mail_processing_failures
message_template = case e
when Email::Receiver::EmptyEmailError then :email_reject_empty
when Email::Receiver::NoBodyDetectedError then :email_reject_empty
when Email::Receiver::NoMessageIdError then :email_reject_no_message_id
when Email::Receiver::AutoGeneratedEmailError then :email_reject_auto_generated
when Email::Receiver::InactiveUserError then :email_reject_inactive_user
when Email::Receiver::BadDestinationAddress then :email_reject_bad_destination_address
when Email::Receiver::StrangersNotAllowedError then :email_reject_strangers_not_allowed
when Email::Receiver::InsufficientTrustLevelError then :email_reject_insufficient_trust_level
when Email::Receiver::ReplyUserNotMatchingError then :email_reject_reply_user_not_matching
when Email::Receiver::TopicNotFoundError then :email_reject_topic_not_found
when Email::Receiver::TopicClosedError then :email_reject_topic_closed
when Email::Receiver::InvalidPost then :email_reject_invalid_post
when ActiveRecord::Rollback then :email_reject_invalid_post
when Email::Receiver::InvalidPostAction then :email_reject_invalid_post_action
when Discourse::InvalidAccess then :email_reject_invalid_access
end
template_args = {}
case e
when Email::Receiver::UserNotSufficientTrustLevelError
message_template = :email_reject_trust_level
when Email::Receiver::UserNotFoundError
message_template = :email_reject_no_account
when Email::Receiver::EmptyEmailError
message_template = :email_reject_empty
when Email::Receiver::EmailUnparsableError
message_template = :email_reject_parsing
when Email::Receiver::EmailLogNotFound
message_template = :email_reject_reply_key
when Email::Receiver::BadDestinationAddress
message_template = :email_reject_destination
when Email::Receiver::TopicNotFoundError
message_template = :email_reject_topic_not_found
when Email::Receiver::TopicClosedError
message_template = :email_reject_topic_closed
when Email::Receiver::AutoGeneratedEmailError
message_template = :email_reject_auto_generated
when Discourse::InvalidAccess
message_template = :email_reject_invalid_access
when ActiveRecord::Rollback
message_template = :email_reject_post_error
when Email::Receiver::InvalidPost
if e.message.length < 6
message_template = :email_reject_post_error
else
message_template = :email_reject_post_error_specified
template_args[:post_error] = e.message
end
else
message_template = nil
# there might be more information available in the exception
if message_template == :email_reject_invalid_post && e.message.size > 6
message_template = :email_reject_invalid_post_specified
template_args[:post_error] = e.message
end
if message_template
@ -81,19 +68,16 @@ module Jobs
end
def poll_pop3
connection = Net::POP3.new(SiteSetting.pop3_polling_host, SiteSetting.pop3_polling_port)
connection.enable_ssl if SiteSetting.pop3_polling_ssl
pop3 = Net::POP3.new(SiteSetting.pop3_polling_host, SiteSetting.pop3_polling_port)
pop3.enable_ssl if SiteSetting.pop3_polling_ssl
connection.start(SiteSetting.pop3_polling_username, SiteSetting.pop3_polling_password) do |pop|
unless pop.mails.empty?
pop.each { |mail| handle_mail(mail) }
pop3.start(SiteSetting.pop3_polling_username, SiteSetting.pop3_polling_password) do |pop|
pop.delete_all do |p|
process_popmail(p)
end
pop.finish
end
rescue Net::POPAuthenticationError => e
Discourse.handle_job_exception(e, error_context(@args, "Signing in to poll incoming email"))
rescue Net::POPError => e
Discourse.handle_job_exception(e, error_context(@args, "Generic POP error"))
end
end

View file

@ -3,13 +3,23 @@ require_dependency 'email/message_builder'
class RejectionMailer < ActionMailer::Base
include Email::BuildEmailHelper
DISALLOWED_TEMPLATE_ARGS = [:to, :from, :base_url,
DISALLOWED_TEMPLATE_ARGS = [:to,
:from,
:base_url,
:user_preferences_url,
:include_respond_instructions, :html_override,
:add_unsubscribe_link, :respond_instructions,
:style, :body, :post_id, :topic_id, :subject,
:template, :allow_reply_by_email,
:private_reply, :from_alias]
:include_respond_instructions,
:html_override,
:add_unsubscribe_link,
:respond_instructions,
:style,
:body,
:post_id,
:topic_id,
:subject,
:template,
:allow_reply_by_email,
:private_reply,
:from_alias]
# Send an email rejection message.
#

View file

@ -0,0 +1,32 @@
class IncomingEmail < ActiveRecord::Base
belongs_to :user
belongs_to :topic
belongs_to :post
scope :errored, -> { where.not(error: nil) }
end
# == Schema Information
#
# Table name: incoming_emails
#
# id :integer not null, primary key
# user_id :integer
# topic_id :integer
# post_id :integer
# raw :text
# error :text
# message_id :text
# from_address :text
# to_addresses :text
# cc_addresses :text
# subject :text
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_incoming_emails_on_created_at (created_at)
# index_incoming_emails_on_error (error)
# index_incoming_emails_on_message_id (message_id)
#

View file

@ -514,6 +514,12 @@ class Topic < ActiveRecord::Base
true
end
def add_small_action(user, action_code, who=nil)
custom_fields = {}
custom_fields["action_code_who"] = who if who.present?
add_moderator_post(user, nil, post_type: Post.types[:small_action], action_code: action_code, custom_fields: custom_fields)
end
def add_moderator_post(user, text, opts=nil)
opts ||= {}
new_post = nil
@ -562,14 +568,7 @@ class Topic < ActiveRecord::Base
topic_user = topic_allowed_users.find_by(user_id: user.id)
if topic_user
topic_user.destroy
# add small action
self.add_moderator_post(
removed_by,
nil,
post_type: Post.types[:small_action],
action_code: "removed_user",
custom_fields: { action_code_who: user.username }
)
add_small_action(removed_by, "removed_user", user.username)
return true
end
end
@ -584,13 +583,7 @@ class Topic < ActiveRecord::Base
user = User.find_by_username_or_email(username_or_email)
if user && topic_allowed_users.create!(user_id: user.id)
# Create a small action message
self.add_moderator_post(
invited_by,
nil,
post_type: Post.types[:small_action],
action_code: "invited_user",
custom_fields: { action_code_who: user.username }
)
add_small_action(invited_by, "invited_user", user.username)
# Notify the user they've been invited
user.notifications.create(notification_type: Notification.types[:invited_to_private_message],

View file

@ -169,8 +169,7 @@ class User < ActiveRecord::Base
def self.suggest_name(email)
return "" if email.blank?
name = email.split(/[@\+]/)[0].gsub(".", " ")
name.titleize
email[/\A[^@]+/].tr(".", " ").titleize
end
def self.find_by_username_or_email(username_or_email)

View file

@ -0,0 +1,32 @@
class IncomingEmailSerializer < ApplicationSerializer
attributes :id,
:created_at,
:from_address,
:to_addresses,
:cc_addresses,
:subject,
:error,
:post_url
has_one :user, serializer: BasicUserSerializer, embed: :objects
def post_url
object.post.url
end
def include_post_url?
object.post.present?
end
def to_addresses
return if object.to_addresses.blank?
object.to_addresses.split(";")
end
def cc_addresses
return if object.cc_addresses.blank?
object.cc_addresses.split(";")
end
end

View file

@ -18,7 +18,8 @@ class SpamRule::AutoBlock
def block?
@user.blocked? or
(!@user.has_trust_level?(TrustLevel[1]) and
(!@user.staged? and
!@user.has_trust_level?(TrustLevel[1]) and
SiteSetting.num_flags_to_block_new_user > 0 and
SiteSetting.num_users_to_block_new_user > 0 and
num_spam_flags_against_user >= SiteSetting.num_flags_to_block_new_user and

View file

@ -21,6 +21,8 @@ class SpamRule::FlagSockpuppets
!first_post.user.staff? &&
!@post.user.staff? &&
!first_post.user.staged? &&
!@post.user.staged? &&
@post.user != first_post.user &&
@post.user.ip_address == first_post.user.ip_address &&
@post.user.new_user? &&

View file

@ -2190,14 +2190,17 @@ en:
email:
title: "Email"
title: "Emails"
settings: "Settings"
all: "All"
templates: "Templates"
preview_digest: "Preview Digest"
sending_test: "Sending test Email..."
error: "<b>ERROR</b> - %{server_error}"
test_error: "There was a problem sending the test email. Please double-check your mail settings, verify that your host is not blocking mail connections, and try again."
sent: "Sent"
skipped: "Skipped"
received: "Received"
rejected: "Rejected"
sent_at: "Sent At"
time: "Time"
user: "User"
@ -2207,7 +2210,6 @@ en:
send_test: "Send Test Email"
sent_test: "sent!"
delivery_method: "Delivery Method"
preview_digest: "Preview Digest"
preview_digest_desc: "Preview the content of the digest emails sent to inactive users."
refresh: "Refresh"
format: "Format"
@ -2216,6 +2218,19 @@ en:
last_seen_user: "Last Seen User:"
reply_key: "Reply Key"
skipped_reason: "Skip Reason"
incoming_emails:
from_address: "From"
to_addresses: "To"
cc_addresses: "Cc"
subject: "Subject"
error: "Error"
none: "No incoming emails found."
filters:
from_placeholder: "from@example.com"
to_placeholder: "to@example.com"
cc_placeholder: "cc@example.com"
subject_placeholder: "Subject..."
error_placeholder: "Error"
logs:
none: "No logs found."
filters:

View file

@ -945,8 +945,6 @@ en:
verbose_localization: "Show extended localization tips in the UI"
previous_visit_timeout_hours: "How long a visit lasts before we consider it the 'previous' visit, in hours"
allow_staged_accounts: "[BETA] Automatically create staged accounts for incoming emails."
rate_limit_create_topic: "After creating a topic, users must wait (n) seconds before creating another topic."
rate_limit_create_post: "After posting, users must wait (n) seconds before creating another post."
rate_limit_new_user_create_topic: "After creating a topic, new users must wait (n) seconds before creating another topic."
@ -1744,13 +1742,34 @@ en:
subject_template: "Data export failed"
text_body_template: "We're sorry, but your data export failed. Please check the logs or contact a staff member."
email_reject_trust_level:
email_reject_insufficient_trust_level:
subject_template: "[%{site_name}] Email issue -- Insufficient Trust Level"
text_body_template: |
We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work.
Your account does not have the required trust level to post new topics to this email address. If you believe this is in error, contact a staff member.
email_reject_inactive_user:
subject_template: "[%{site_name}] Email issue -- Inactive User"
text_body_template: |
We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work.
Your account associated with this email address is not activated. Please activate your account before sending emails in.
email_reject_reply_user_not_matching:
subject_template: "[%{site_name}] Email issue -- Reply User Not Matching"
text_body_template: |
We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work.
The original notification was not sent to this email address. Try sending from a different email address, or contact a staff member.
email_reject_no_message_id:
subject_template: "[%{site_name}] Email issue -- No Message Id"
text_body_template: |
We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work.
There was no Message-Id header in the email. Try sending from a different email address, or contact a staff member.
email_reject_no_account:
subject_template: "[%{site_name}] Email issue -- Unknown Account"
text_body_template: |
@ -1781,14 +1800,21 @@ en:
Your account does not have the privileges to post new topics in that category. If you believe this is in error, contact a staff member.
email_reject_post_error:
email_reject_strangers_not_allowed:
subject_template: "[%{site_name}] Email issue -- Invalid Access"
text_body_template: |
We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work.
The category you sent this email to does not allow emails from unrestricted accounts. If you believe this is in error, contact a staff member.
email_reject_invalid_post:
subject_template: "[%{site_name}] Email issue -- Posting error"
text_body_template: |
We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work.
Some possible causes are: complex formatting, message too large, message too small. Please try again, or post via the website if this continues.
email_reject_post_error_specified:
email_reject_invalid_post_specified:
subject_template: "[%{site_name}] Email issue -- Posting error"
text_body_template: |
We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work.
@ -1799,6 +1825,14 @@ en:
If you can correct the problem, please try again.
email_reject_invalid_post_action:
subject_template: "[%{site_name}] Email issue -- Invalid Post Action"
text_body_template: |
We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work.
The Post Action was not recognized. Please try again, or post via the website if this continues.
email_reject_reply_key:
subject_template: "[%{site_name}] Email issue -- Unknown Reply Key"
text_body_template: |
@ -1806,12 +1840,12 @@ en:
The provided reply key is invalid or unknown, so we don't know what this email is in reply to. Contact a staff member.
email_reject_destination:
email_reject_bad_destination_address:
subject_template: "[%{site_name}] Email issue -- Unknown To: Address"
text_body_template: |
We're sorry, but your email message to %{destination} (titled %{former_title}) didn't work.
None of the destination addresses are recognized. Please make sure that the site address is in the To: line (not Cc: or Bcc:), and that you are sending to the correct email address provided by staff.
None of the destination addresses are recognized. Please make sure that you are sending to the correct email address provided by staff.
email_reject_topic_not_found:
subject_template: "[%{site_name}] Email issue -- Topic Not Found"

View file

@ -119,9 +119,10 @@ Discourse::Application.routes.draw do
resources :email, constraints: AdminConstraint.new do
collection do
post "test"
get "all"
get "sent"
get "skipped"
get "received"
get "rejected"
get "preview-digest" => "email#preview_digest"
post "handle_mail"
end

View file

@ -806,8 +806,6 @@ developer:
default: 500
client: true
hidden: true
allow_staged_accounts:
default: false
embedding:
feed_polling_enabled:

View file

@ -10,6 +10,6 @@ class DropGroupManagers < ActiveRecord::Migration
end
def down
raise ActiveRecord::IrriversableMigration
raise ActiveRecord::IrreversibleMigration
end
end

View file

@ -0,0 +1,24 @@
class CreateIncomingEmails < ActiveRecord::Migration
def change
create_table :incoming_emails do |t|
t.integer :user_id
t.integer :topic_id
t.integer :post_id
t.text :raw
t.text :error
t.text :message_id
t.text :from_address
t.text :to_addresses
t.text :cc_addresses
t.text :subject
t.timestamps null: false
end
add_index :incoming_emails, :created_at
add_index :incoming_emails, :message_id
add_index :incoming_emails, :error
end
end

View file

@ -0,0 +1,28 @@
class BackfillIncomingEmails < ActiveRecord::Migration
def up
execute <<-SQL
INSERT INTO incoming_emails (post_id, created_at, updated_at, user_id, topic_id, message_id, from_address, to_addresses, subject)
SELECT posts.id
, posts.created_at
, posts.created_at
, posts.user_id
, posts.topic_id
, array_to_string(regexp_matches(posts.raw_email, '^\s*Message-Id: .*<([^>]+)>', 'im'), '')
, users.email
, array_to_string(regexp_matches(array_to_string(regexp_matches(posts.raw_email, '^to:.+$', 'im'), ''), '[^<\s"''(]+@[^>\s"'')]+'), '')
, topics.title
FROM posts
JOIN topics ON posts.topic_id = topics.id
JOIN users ON posts.user_id = users.id
WHERE posts.user_id IS NOT NULL
AND posts.topic_id IS NOT NULL
AND posts.via_email = 't'
AND posts.raw_email ~* 'Message-Id'
ORDER BY posts.id;
SQL
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View file

@ -16,9 +16,7 @@
{ "path": "script" },
{ "path": "spec" },
{ "path": "vendor" },
{ "path": "test",
"folder_exclude_patterns": ["fixtures"]
}
{ "path": "test" },
],
"settings":
{

View file

@ -48,7 +48,7 @@ module BackupRestore
switch_schema!
migrate_database
# migrate_database
reconnect_database
reload_site_settings
clear_emoji_cache
@ -56,7 +56,7 @@ module BackupRestore
disable_readonly_mode
### READ-ONLY / END ###
extract_uploads
# extract_uploads
rescue SystemExit
log "Restore process was cancelled!"
rollback

View file

@ -1,144 +1,198 @@
require_dependency 'new_post_manager'
require_dependency 'email/html_cleaner'
require_dependency 'post_action_creator'
require_dependency "new_post_manager"
require_dependency "post_action_creator"
require_dependency "email/html_cleaner"
module Email
class Receiver
include ActionView::Helpers::NumberHelper
class ProcessingError < StandardError; end
class EmptyEmailError < ProcessingError; end
class NoMessageIdError < ProcessingError; end
class AutoGeneratedEmailError < ProcessingError; end
class NoBodyDetectedError < ProcessingError; end
class InactiveUserError < ProcessingError; end
class BadDestinationAddress < ProcessingError; end
class StrangersNotAllowedError < ProcessingError; end
class InsufficientTrustLevelError < ProcessingError; end
class ReplyUserNotMatchingError < ProcessingError; end
class TopicNotFoundError < ProcessingError; end
class TopicClosedError < ProcessingError; end
class InvalidPost < ProcessingError; end
class InvalidPostAction < ProcessingError; end
class ProcessingError < StandardError; end
class EmailUnparsableError < ProcessingError; end
class EmptyEmailError < ProcessingError; end
class UserNotFoundError < ProcessingError; end
class UserNotSufficientTrustLevelError < ProcessingError; end
class BadDestinationAddress < ProcessingError; end
class TopicNotFoundError < ProcessingError; end
class TopicClosedError < ProcessingError; end
class AutoGeneratedEmailError < ProcessingError; end
class EmailLogNotFound < ProcessingError; end
class InvalidPost < ProcessingError; end
class ReplyUserNotFoundError < ProcessingError; end
class ReplyUserNotMatchingError < ProcessingError; end
class InactiveUserError < ProcessingError; end
class InvalidPostAction < ProcessingError; end
attr_reader :body, :email_log
def initialize(raw, opts=nil)
@raw = raw
@opts = opts || {}
def initialize(mail_string)
raise EmptyEmailError if mail_string.blank?
@raw_email = mail_string
@mail = Mail.new(@raw_email)
raise NoMessageIdError if @mail.message_id.blank?
end
def process
raise EmptyEmailError if @raw.blank?
@message = Mail.new(@raw)
raise AutoGeneratedEmailError if @message.header.to_s =~ /auto-(replied|generated)/
@body = parse_body(@message)
# 'smtp_envelope_to' is a combination of: to, cc and bcc fields
# prioriziting the `:reply` types
dest_infos = @message.smtp_envelope_to
.map { |to_address| check_address(to_address) }
.compact
.sort do |a, b|
if a[:type] == :reply && b[:type] != :reply
1
elsif a[:type] != :reply && b[:type] == :reply
-1
else
0
end
end
raise BadDestinationAddress if dest_infos.empty?
from = @message[:from].address_list.addresses.first
user_email = from.address
user_name = from.display_name
user = User.find_by_email(user_email)
raise InactiveUserError if user.present? && !user.active && !user.staged
# TODO: take advantage of all the "TO"s
dest_info = dest_infos[0]
case dest_info[:type]
when :group
group = dest_info[:obj]
if user.blank?
if SiteSetting.allow_staged_accounts
user = create_staged_account(user_email, user_name)
else
wrap_body_in_quote(user_email)
user = Discourse.system_user
end
end
create_new_topic(user, archetype: Archetype.private_message, target_group_names: [group.name])
when :category
category = dest_info[:obj]
if user.blank? && category.email_in_allow_strangers
if SiteSetting.allow_staged_accounts
user = create_staged_account(user_email)
else
wrap_body_in_quote(user_email)
user = Discourse.system_user
end
end
raise UserNotFoundError if user.blank?
raise UserNotSufficientTrustLevelError.new(user) unless category.email_in_allow_strangers || user.has_trust_level?(TrustLevel[SiteSetting.email_in_min_trust.to_i])
create_new_topic(user, category: category.id)
when :reply
@email_log = dest_info[:obj]
raise EmailLogNotFound if @email_log.blank?
raise TopicNotFoundError if Topic.find_by_id(@email_log.topic_id).nil?
raise TopicClosedError if Topic.find_by_id(@email_log.topic_id).closed?
raise ReplyUserNotFoundError if user.blank?
raise ReplyUserNotMatchingError if @email_log.user_id != user.id
if post_action_type = post_action_for(@body)
create_post_action(@email_log, post_action_type)
else
create_reply(@email_log)
end
end
rescue Encoding::UndefinedConversionError, Encoding::InvalidByteSequenceError => e
raise EmailUnparsableError.new(e)
@incoming_email = find_or_create_incoming_email
process_internal
rescue => e
@incoming_email.update_columns(error: e.to_s)
raise
end
def create_staged_account(email, name=nil)
User.create(
email: email,
username: UserNameSuggester.suggest(name.presence || email),
name: name.presence || User.suggest_name(email),
staged: true,
)
def find_or_create_incoming_email
IncomingEmail.find_or_create_by(message_id: @mail.message_id) do |incoming_email|
incoming_email.raw = @raw_email
incoming_email.subject = @mail.subject
incoming_email.from_address = @mail.from.first.downcase
incoming_email.to_addresses = @mail.to.map(&:downcase).join(";") if @mail.to.present?
incoming_email.cc_addresses = @mail.cc.map(&:downcase).join(";") if @mail.cc.present?
end
end
def process_internal
raise AutoGeneratedEmailError if is_auto_generated?
body = select_body || ""
raise NoBodyDetectedError if body.blank? && !@mail.has_attachments?
user = find_or_create_user(from)
@incoming_email.update_columns(user_id: user.id)
raise InactiveUserError if !user.active && !user.staged
if post = find_related_post
create_reply(user: user, raw: body, post: post, topic: post.topic)
else
destination = destinations.first
raise BadDestinationAddress if destination.blank?
case destination[:type]
when :group
group = destination[:obj]
create_topic(user: user, raw: body, title: @mail.subject, archetype: Archetype.private_message, target_group_names: [group.name], skip_validations: true)
when :category
category = destination[:obj]
raise StrangersNotAllowedError if user.staged? && !category.email_in_allow_strangers
raise InsufficientTrustLevelError if !user.has_trust_level?(SiteSetting.email_in_min_trust)
create_topic(user: user, raw: body, title: @mail.subject, category: category.id)
when :reply
email_log = destination[:obj]
raise ReplyUserNotMatchingError if email_log.user_id != user.id
create_reply(user: user, raw: body, post: email_log.post, topic: email_log.post.topic)
end
end
end
def is_auto_generated?
@mail.return_path.blank? ||
@mail[:precedence].to_s[/list|junk|bulk|auto_reply/] ||
@mail.header.to_s[/auto-(submitted|replied|generated)/]
end
def select_body
text = nil
html = nil
if @mail.multipart?
text = fix_charset(@mail.text_part)
html = fix_charset(@mail.html_part)
elsif @mail.content_type.to_s["text/html"]
html = fix_charset(@mail)
else
text = fix_charset(@mail)
end
# prefer text over html
if text.present?
text_encoding = text.encoding
text = DiscourseEmailParser.parse_reply(text)
text = try_to_encode(text, text_encoding)
return text if text.present?
end
# clean the html if that's all we've got
if html.present?
html_encoding = html.encoding
html = Email::HtmlCleaner.new(html).output_html
html = DiscourseEmailParser.parse_reply(html)
html = try_to_encode(html, html_encoding)
return html if html.present?
end
end
def fix_charset(mail_part)
return nil if mail_part.blank? || mail_part.body.blank?
string = mail_part.body.to_s
# TODO (use charlock_holmes to properly detect encoding)
# 1) use the charset provided
if mail_part.charset.present?
fixed = try_to_encode(string, mail_part.charset)
return fixed if fixed.present?
end
# 2) default to UTF-8
try_to_encode(string, "UTF-8")
end
def try_to_encode(string, encoding)
string.encode("UTF-8", encoding)
rescue Encoding::InvalidByteSequenceError, Encoding::UndefinedConversionError
nil
end
def from
@from ||= @mail[:from].address_list.addresses.first
end
def find_or_create_user(address_field)
# decode the address field
address_field.decoded
# extract email and name
email = address_field.address.downcase
name = address_field.display_name.try(:to_s)
username = UserNameSuggester.sanitize_username(name) if name.present?
User.find_or_create_by(email: email) do |user|
user.username = UserNameSuggester.suggest(username.presence || email)
user.name = name.presence || User.suggest_name(email)
user.staged = true
end
end
def destinations
[ @mail.destinations,
[@mail[:x_forwarded_to]].flatten.compact.map(&:decoded),
[@mail[:delivered_to]].flatten.compact.map(&:decoded),
].flatten
.select(&:present?)
.uniq
.lazy
.map { |d| check_address(d) }
.drop_while(&:blank?)
end
def check_address(address)
# only check for a group/category when 'email_in' is enabled
if SiteSetting.email_in
group = Group.find_by_email(address)
return { address: address, type: :group, obj: group } if group
return { type: :group, obj: group } if group
category = Category.find_by_email(address)
return { address: address, type: :category, obj: category } if category
return { type: :category, obj: category } if category
end
# reply
match = reply_by_email_address_regex.match(address)
if match && match[1].present?
email_log = EmailLog.for(match[1])
return { address: address, type: :reply, obj: email_log }
return { type: :reply, obj: email_log } if email_log
end
end
@ -147,173 +201,89 @@ module Email
.gsub(Regexp.escape("%{reply_key}"), "([[:xdigit:]]{32})")
end
def parse_body(message)
body = select_body(message)
encoding = body.encoding
raise EmptyEmailError if body.strip.blank?
def find_related_post
message_ids = [@mail.in_reply_to, extract_references]
message_ids.flatten!
message_ids.select!(&:present?)
message_ids.uniq!
return if message_ids.empty?
body = discourse_email_trimmer(body)
raise EmptyEmailError if body.strip.blank?
body = DiscourseEmailParser.parse_reply(body)
raise EmptyEmailError if body.strip.blank?
body.force_encoding(encoding).encode("UTF-8")
IncomingEmail.where.not(post_id: nil)
.where(message_id: message_ids)
.first
.try(:post)
end
def select_body(message)
html = nil
if message.multipart?
text = fix_charset message.text_part
# prefer text over html
return text if text
html = fix_charset message.html_part
elsif message.content_type =~ /text\/html/
html = fix_charset message
def extract_references
if Array === @mail.references
@mail.references
elsif @mail.references.present?
@mail.references.split(/[\s,]/).map { |r| r.sub(/^</, "").sub(/>$/, "") }
end
if html
body = HtmlCleaner.new(html).output_html
else
body = fix_charset message
end
return body if @opts[:skip_sanity_check]
# Certain trigger phrases that means we didn't parse correctly
if body =~ /Content\-Type\:/ || body =~ /multipart\/alternative/ || body =~ /text\/plain/
raise EmptyEmailError
end
body
end
# Force encoding to UTF-8 on a Mail::Message or Mail::Part
def fix_charset(object)
return nil if object.nil?
if object.charset
object.body.decoded.force_encoding(object.charset.gsub(/utf8/i, "UTF-8")).encode("UTF-8").to_s
else
object.body.to_s
end
rescue
nil
end
REPLYING_HEADER_LABELS = ['From', 'Sent', 'To', 'Subject', 'In-Reply-To', 'Cc', 'Bcc', 'Date']
REPLYING_HEADER_REGEX = Regexp.union(REPLYING_HEADER_LABELS.map { |lbl| "#{lbl}:" })
def line_is_quote?(l)
l =~ /\A\s*\-{3,80}\s*\z/ ||
l =~ Regexp.new("\\A\\s*" + I18n.t('user_notifications.previous_discussion') + "\\s*\\Z") ||
(l =~ /via #{SiteSetting.title}(.*)\:$/) ||
# This one might be controversial but so many reply lines have years, times and end with a colon.
# Let's try it and see how well it works.
(l =~ /\d{4}/ && l =~ /\d:\d\d/ && l =~ /\:$/) ||
(l =~ /On [\w, ]+\d+.*wrote:/)
end
def discourse_email_trimmer(body)
lines = body.scrub.lines.to_a
range_start = 0
range_end = 0
# If we started with a quote, skip it
lines.each_with_index do |l, idx|
break unless line_is_quote?(l) or l =~ /^>/ or l.blank?
range_start = idx + 1
end
lines[range_start..-1].each_with_index do |l, idx|
break if line_is_quote?(l)
# Headers on subsequent lines
break if (0..2).all? { |off| lines[idx+off] =~ REPLYING_HEADER_REGEX }
# Headers on the same line
break if REPLYING_HEADER_LABELS.count { |lbl| l.include? lbl } >= 3
range_end = range_start + idx
end
lines[range_start..range_end].join.strip
end
private
def wrap_body_in_quote(user_email)
@body = "[quote=\"#{user_email}\"]\n#{@body}\n[/quote]"
end
def create_post_action(email_log, type)
PostActionCreator.new(email_log.user, email_log.post).perform(type)
rescue Discourse::InvalidAccess, PostAction::AlreadyActed => e
raise InvalidPostAction.new(e)
def likes
@likes ||= Set.new ["+1", I18n.t('post_action_types.like.title').downcase]
end
def post_action_for(body)
if ['+1', I18n.t('post_action_types.like.title').downcase].include? body.downcase
if likes.include?(body.strip.downcase)
PostActionType.types[:like]
end
end
def create_reply(email_log)
create_post_with_attachments(email_log.user,
raw: @body,
topic_id: email_log.topic_id,
reply_to_post_number: email_log.post.post_number)
def create_topic(options={})
create_post_with_attachments(options)
end
def create_new_topic(user, topic_options={})
topic_options[:raw] = @body
topic_options[:title] = @message.subject
def create_reply(options={})
raise TopicNotFoundError if options[:topic].nil? || options[:topic].trashed?
raise TopicClosedError if options[:topic].closed?
result = create_post_with_attachments(user, topic_options)
topic_id = result.post.present? ? result.post.topic_id : nil
EmailLog.create(
email_type: "topic_via_incoming_email",
to_address: user.email,
topic_id: topic_id,
user_id: user.id,
)
result
if post_action_type = post_action_for(options[:raw])
create_post_action(options[:user], options[:post], post_action_type)
else
options[:topic_id] = options[:post].try(:topic_id)
options[:reply_to_post_number] = options[:post].try(:post_number)
create_post_with_attachments(options)
end
end
def create_post_with_attachments(user, post_options={})
options = {
cooking_options: { traditional_markdown_linebreaks: true },
}.merge(post_options)
raw = options[:raw]
def create_post_action(user, post, type)
PostActionCreator.new(user, post).perform(type)
rescue PostAction::AlreadyActed
# it's cool, don't care
rescue Discourse::InvalidAccess => e
raise InvalidPostAction.new(e)
end
def create_post_with_attachments(options={})
# deal with attachments
@message.attachments.each do |attachment|
@mail.attachments.each do |attachment|
tmp = Tempfile.new("discourse-email-attachment")
begin
# read attachment
File.open(tmp.path, "w+b") { |f| f.write attachment.body.decoded }
# create the upload for the user
upload = Upload.create_for(user.id, tmp, attachment.filename, tmp.size)
upload = Upload.create_for(options[:user].id, tmp, attachment.filename, tmp.size)
if upload && upload.errors.empty?
# try to inline images
if attachment.content_type.start_with?("image/")
if raw =~ /\[image: Inline image \d+\]/
raw.sub!(/\[image: Inline image \d+\]/, attachment_markdown(upload))
next
end
if attachment.content_type.start_with?("image/") && options[:raw][/\[image: .+ \d+\]/]
options[:raw].sub!(/\[image: .+ \d+\]/, attachment_markdown(upload))
else
options[:raw] << "\n#{attachment_markdown(upload)}\n"
end
raw << "\n#{attachment_markdown(upload)}\n"
end
ensure
tmp.close!
tmp.try(:close!) rescue nil
end
end
options[:raw] = raw
post_options = {
cooking_options: { traditional_markdown_linebreaks: true },
}.merge(options)
create_post(user, options)
create_post(post_options)
end
def attachment_markdown(upload)
@ -324,20 +294,46 @@ module Email
end
end
def create_post(user, options)
# Mark the reply as incoming via email
def create_post(options={})
options[:via_email] = true
options[:raw_email] = @raw
options[:raw_email] = @raw_email
manager = NewPostManager.new(user, options)
# ensure posts aren't created in the future
options[:created_at] = [@mail.date, DateTime.now].min
manager = NewPostManager.new(options[:user], options)
result = manager.perform
if result.errors.present?
raise InvalidPost, result.errors.full_messages.join("\n")
end
raise InvalidPost, result.errors.full_messages.join("\n") if result.errors.any?
result
if result.post
@incoming_email.update_columns(topic_id: result.post.topic_id, post_id: result.post.id)
if result.post.topic && result.post.topic.private_message?
add_other_addresses(result.post.topic, options[:user])
end
end
end
def add_other_addresses(topic, sender)
%i(to cc bcc).each do |d|
if @mail[d] && @mail[d].address_list && @mail[d].address_list.addresses
@mail[d].address_list.addresses.each do |address|
begin
if user = find_or_create_user(address)
unless topic.topic_allowed_users.where(user_id: user.id).exists? &&
topic.topic_allowed_groups.where("group_id IN (SELECT group_id FROM group_users WHERE user_id = ?)", user.id).exists?
topic.topic_allowed_users.create!(user_id: user.id)
topic.add_small_action(sender, "invited_user", user.username)
end
end
rescue ActiveRecord::RecordInvalid
# don't care if user already allowed
end
end
end
end
end
end
end

56
lib/tasks/emails.rake Normal file
View file

@ -0,0 +1,56 @@
def process_popmail(popmail)
begin
mail_string = popmail.pop
Email::Receiver.new(mail_string).process
rescue
putc "!"
else
putc "."
end
end
desc "use this task to import a mailbox into Disourse"
task "emails:import" => :environment do
begin
unless SiteSetting.email_in
puts "ERROR: you should enable the 'email_in' site setting before running this task"
exit(1)
end
address = ENV["ADDRESS"].presence || "pop.gmail.com"
port = (ENV["PORT"].presence || 995).to_i
ssl = (ENV["SSL"].presence || "1") == "1"
username = ENV["USERNAME"].presence
password = ENV["PASSWORD"].presence
if username.blank?
puts "ERROR: expecting USERNAME=<username> rake emails:import"
exit(2)
elsif password.blank?
puts "ERROR: expecting PASSWORD=<password> rake emails:import"
exit(3)
end
RateLimiter.disable
mails_left = 1
pop3 = Net::POP3.new(address, port)
pop3.enable_ssl if ssl
while mails_left > 0
pop3.start(username, password) do |pop|
pop.delete_all do |p|
process_popmail(p)
end
mails_left = pop.n_mails
end
end
puts "Done"
rescue Net::POPAuthenticationError
puts "AUTH EXCEPTION: please make sure your credentials are correct."
exit(10)
ensure
RateLimiter.enable
end
end

View file

@ -193,6 +193,6 @@ class TopicCreator
end
def check_can_send_permission!(topic, obj)
rollback_with!(topic, :cant_send_pm) unless @guardian.can_send_private_message?(obj)
rollback_with!(topic, :cant_send_pm) unless @opts[:skip_validations] || @guardian.can_send_private_message?(obj)
end
end

View file

@ -34,12 +34,11 @@ module UserNameSuggester
end
def self.sanitize_username(name)
name = ActiveSupport::Inflector.transliterate(name)
name = name.gsub(/^[^[:alnum:]]+|\W+$/, "")
.gsub(/\W+/, "_")
.gsub(/^\_+/, '')
.gsub(/[\-_\.]{2,}/, "_")
name
ActiveSupport::Inflector.transliterate(name)
.gsub(/^[^[:alnum:]]+|\W+$/, "")
.gsub(/\W+/, "_")
.gsub(/^\_+/, '')
.gsub(/[\-_\.]{2,}/, "_")
end
def self.rightsize_username(name)

View file

@ -1,791 +1,233 @@
# -*- encoding : utf-8 -*-
require 'rails_helper'
require 'email/receiver'
require "rails_helper"
require "email/receiver"
describe Email::Receiver do
before do
SiteSetting.reply_by_email_address = "reply+%{reply_key}@appmail.adventuretime.ooo"
SiteSetting.email_in = false
SiteSetting.title = "Discourse"
SiteSetting.email_in = true
SiteSetting.reply_by_email_address = "reply+%{reply_key}@bar.com"
end
describe 'parse_body' do
def test_parse_body(mail_string)
Email::Receiver.new(nil).parse_body(Mail::Message.new mail_string)
def email(email_name)
fixture_file("emails/#{email_name}.eml")
end
def process(email_name)
Email::Receiver.new(email(email_name)).process
end
it "raises an EmptyEmailError when 'mail_string' is blank" do
expect { Email::Receiver.new(nil) }.to raise_error(Email::Receiver::EmptyEmailError)
expect { Email::Receiver.new("") }.to raise_error(Email::Receiver::EmptyEmailError)
end
it "raises an NoMessageIdError when 'mail_string' is not an email" do
expect { Email::Receiver.new("wat") }.to raise_error(Email::Receiver::NoMessageIdError)
end
it "raises an NoMessageIdError when 'mail_string' is missing the message_id" do
expect { Email::Receiver.new(email(:missing_message_id)) }.to raise_error(Email::Receiver::NoMessageIdError)
end
it "raises an AutoGeneratedEmailError when the mail has no return path" do
expect { process(:no_return_path) }.to raise_error(Email::Receiver::AutoGeneratedEmailError)
end
it "raises an AutoGeneratedEmailError when the mail is auto generated" do
expect { process(:auto_generated_precedence) }.to raise_error(Email::Receiver::AutoGeneratedEmailError)
expect { process(:auto_generated_header) }.to raise_error(Email::Receiver::AutoGeneratedEmailError)
end
it "raises a NoBodyDetectedError when the body is blank" do
expect { process(:no_body) }.to raise_error(Email::Receiver::NoBodyDetectedError)
end
it "raises an InactiveUserError when the sender is inactive" do
Fabricate(:user, email: "inactive@bar.com", active: false)
expect { process(:inactive_sender) }.to raise_error(Email::Receiver::InactiveUserError)
end
skip "doesn't raise an InactiveUserError when the sender is staged" do
Fabricate(:user, email: "staged@bar.com", active: false, staged: true)
expect { process(:staged_sender) }.not_to raise_error
end
it "raises a BadDestinationAddress when destinations aren't matching any of the incoming emails" do
expect { process(:bad_destinations) }.to raise_error(Email::Receiver::BadDestinationAddress)
end
context "reply" do
let(:reply_key) { "4f97315cc828096c9cb34c6f1a0d6fe8" }
let(:user) { Fabricate(:user, email: "discourse@bar.com") }
let(:topic) { create_topic(user: user) }
let(:post) { create_post(topic: topic, user: user) }
let!(:email_log) { Fabricate(:email_log, reply_key: reply_key, user: user, topic: topic, post: post) }
it "raises a ReplyUserNotMatchingError when the email address isn't matching the one we sent the notification to" do
expect { process(:reply_user_not_matching) }.to raise_error(Email::Receiver::ReplyUserNotMatchingError)
end
it "raises EmptyEmailError if the message is blank" do
expect { test_parse_body("") }.to raise_error(Email::Receiver::EmptyEmailError)
it "raises a TopicNotFoundError when the topic was deleted" do
topic.update_columns(deleted_at: 1.day.ago)
expect { process(:reply_user_matching) }.to raise_error(Email::Receiver::TopicNotFoundError)
end
it "raises EmptyEmailError if the message is not an email" do
expect { test_parse_body("asdf" * 30) }.to raise_error(Email::Receiver::EmptyEmailError)
it "raises a TopicClosedError when the topic was closed" do
topic.update_columns(closed: true)
expect { process(:reply_user_matching) }.to raise_error(Email::Receiver::TopicClosedError)
end
it "raises EmptyEmailError if there is no reply content" do
expect { test_parse_body(fixture_file("emails/no_content_reply.eml")) }.to raise_error(Email::Receiver::EmptyEmailError)
it "raises an InvalidPost when there was an error while creating the post" do
expect { process(:too_small) }.to raise_error(Email::Receiver::InvalidPost)
end
skip "raises EmailUnparsableError if the headers are corrupted" do
expect { ; }.to raise_error(Email::Receiver::EmailUnparsableError)
it "raises an InvalidPost when there are too may mentions" do
SiteSetting.max_mentions_per_post = 1
Fabricate(:user, username: "user1")
Fabricate(:user, username: "user2")
expect { process(:too_many_mentions) }.to raise_error(Email::Receiver::InvalidPost)
end
it "can parse the html section" do
expect(test_parse_body(fixture_file("emails/html_only.eml"))).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.")
it "raises an InvalidPostAction when they aren't allowed to like a post" do
topic.update_columns(archived: true)
expect { process(:like) }.to raise_error(Email::Receiver::InvalidPostAction)
end
it "supports a Dutch reply" do
expect(test_parse_body(fixture_file("emails/dutch.eml"))).to eq("Dit is een antwoord in het Nederlands.")
it "works" do
expect { process(:text_reply) }.to change { topic.posts.count }
expect(topic.posts.last.raw).to eq("This is a text reply :)")
expect(topic.posts.last.via_email).to eq(true)
expect(topic.posts.last.cooked).not_to match(/<br/)
expect { process(:html_reply) }.to change { topic.posts.count }
expect(topic.posts.last.raw).to eq("This is a <b>HTML</b> reply ;)")
expect { process(:hebrew_reply) }.to change { topic.posts.count }
expect(topic.posts.last.raw).to eq("שלום! מה שלומך היום?")
expect { process(:chinese_reply) }.to change { topic.posts.count }
expect(topic.posts.last.raw).to eq("您好! 你今天好吗?")
end
it "supports a Hebrew reply" do
I18n.stubs(:t).with('user_notifications.previous_discussion').returns('כלטוב')
# The force_encoding call is only needed for the test - it is passed on fine to the cooked post
expect(test_parse_body(fixture_file("emails/hebrew.eml"))).to eq("שלום")
it "prefers text over html" do
expect { process(:text_and_html_reply) }.to change { topic.posts.count }
expect(topic.posts.last.raw).to eq("This is the *text* part.")
end
it "supports a BIG5-encoded reply" do
# The force_encoding call is only needed for the test - it is passed on fine to the cooked post
expect(test_parse_body(fixture_file("emails/big5.eml"))).to eq("媽!我上電視了!")
it "removes the 'on <date>, <contact> wrote' quoting line" do
expect { process(:on_date_contact_wrote) }.to change { topic.posts.count }
expect(topic.posts.last.raw).to eq("This is the actual reply.")
end
it "removes 'via' lines if they match the site title" do
SiteSetting.title = "Discourse"
expect(test_parse_body(fixture_file("emails/via_line.eml"))).to eq("Hello this email has content!")
end
it "removes an 'on date wrote' quoting line" do
expect(test_parse_body(fixture_file("emails/on_wrote.eml"))).to eq("Sure, all you need to do is frobnicate the foobar and you'll be all set!")
end
it "removes the 'Previous Discussion' marker" do
expect(test_parse_body(fixture_file("emails/previous.eml"))).to eq("This will not include the previous discussion that is present in this email.")
it "removes the 'Previous Replies' marker" do
expect { process(:previous_replies) }.to change { topic.posts.count }
expect(topic.posts.last.raw).to eq("This will not include the previous discussion that is present in this email.")
end
it "handles multiple paragraphs" do
expect(test_parse_body(fixture_file("emails/paragraphs.eml"))).
to eq(
"Is there any reason the *old* candy can't be be kept in silos while the new candy
is imported into *new* silos?
The thing about candy is it stays delicious for a long time -- we can just keep
it there without worrying about it too much, imo.
Thanks for listening."
)
end
it "handles multiple paragraphs when parsing html" do
expect(test_parse_body(fixture_file("emails/html_paragraphs.eml"))).
to eq(
"Awesome!
Pleasure to have you here!
:boom:"
)
end
it "handles newlines" do
expect(test_parse_body(fixture_file("emails/newlines.eml"))).
to eq(
"This is my reply.
It is my best reply.
It will also be my *only* reply."
)
expect { process(:paragraphs) }.to change { topic.posts.count }
expect(topic.posts.last.raw).to eq("Do you like liquorice?\n\nI really like them. One could even say that I am *addicted* to liquorice. Anf if\nyou can mix it up with some anise, then I'm in heaven ;)")
end
it "handles inline reply" do
expect(test_parse_body(fixture_file("emails/inline_reply.eml"))).
to eq(
"On Wed, Oct 8, 2014 at 11:12 AM, techAPJ <info@unconfigured.discourse.org> wrote:
> techAPJ <https://meta.discourse.org/users/techapj>
> November 28
>
> Test reply.
>
> First paragraph.
>
> Second paragraph.
>
> To respond, reply to this email or visit
> https://meta.discourse.org/t/testing-default-email-replies/22638/3 in
> your browser.
> ------------------------------
> Previous Replies codinghorror
> <https://meta.discourse.org/users/codinghorror>
> November 28
>
> We're testing the latest GitHub email processing library which we are
> integrating now.
>
> https://github.com/github/email_reply_parser
>
> Go ahead and reply to this topic and I'll reply from various email clients
> for testing.
> ------------------------------
>
> To respond, reply to this email or visit
> https://meta.discourse.org/t/testing-default-email-replies/22638/3 in
> your browser.
>
> To unsubscribe from these emails, visit your user preferences
> <https://meta.discourse.org/my/preferences>.
>
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over
the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown
fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over
the lazy dog. The quick brown fox jumps over the lazy dog."
)
expect { process(:inline_reply) }.to change { topic.posts.count }
expect(topic.posts.last.raw).to eq("On Tue, Jan 15, 2016 at 11:12 AM, Bar Foo <info@unconfigured.discourse.org> wrote:\n\n> WAT <https://bar.com/users/wat> November 28\n>\n> This is the previous post.\n\nAnd this is *my* reply :+1:")
end
it "can retrieve the first part of multiple replies" do
expect(test_parse_body(fixture_file("emails/inline_mixed.eml"))).to eq(
"The quick brown fox jumps over the lazy dog. The quick brown fox jumps over
the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown
fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over
the lazy dog. The quick brown fox jumps over the lazy dog.
> First paragraph.
>
> Second paragraph.
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over
the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown"
)
it "retrieves the first part of multiple replies" do
expect { process(:inline_mixed_replies) }.to change { topic.posts.count }
expect(topic.posts.last.raw).to eq("On Tue, Jan 15, 2016 at 11:12 AM, Bar Foo <info@unconfigured.discourse.org> wrote:\n\n> WAT <https://bar.com/users/wat> November 28\n>\n> This is the previous post.\n\nAnd this is *my* reply :+1:\n\n> This is another post.\n\nAnd this is **another** reply.")
end
it "should not include previous replies" do
expect(test_parse_body(fixture_file("emails/previous_replies.eml"))).not_to match(/Previous Replies/)
end
it "strips signatures" do
expect { process(:iphone_signature) }.to change { topic.posts.count }
expect(topic.posts.last.raw).to eq("This is not the signature you're looking for.")
it "strips iPhone signature" do
expect(test_parse_body(fixture_file("emails/iphone_signature.eml"))).not_to match(/Sent from my iPhone/)
end
it "strips regular signature" do
expect(test_parse_body(fixture_file("emails/signature.eml"))).not_to match(/Arpit/)
expect { process(:signature) }.to change { topic.posts.count }
expect(topic.posts.last.raw).to eq("You shall not sign!")
end
it "strips 'original message' context" do
expect(test_parse_body(fixture_file("emails/original_message_context.eml"))).not_to match(/Context/)
expect { process(:original_message) }.to change { topic.posts.count }
expect(topic.posts.last.raw).to eq("This is a reply :)")
end
it "properly renders email reply from gmail web client" do
expect(test_parse_body(fixture_file("emails/gmail_web.eml"))).
to eq(
"### This is a reply from standard GMail in Google Chrome.
it "supports attachments" do
expect { process(:no_body_with_attachments) }.to change { topic.posts.count }
expect(topic.posts.last.raw).to match(/<img/)
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over
the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown
fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over
the lazy dog. The quick brown fox jumps over the lazy dog.
Here's some **bold** text in Markdown.
Here's a link http://example.com"
)
expect { process(:inline_attachment) }.to change { topic.posts.count }
expect(topic.posts.last.raw).to match(/Before\s+<img.+\s+After/m)
end
it "properly renders email reply from iOS default mail client" do
expect(test_parse_body(fixture_file("emails/ios_default.eml"))).
to eq(
"### this is a reply from iOS default mail
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.
Here's some **bold** markdown text.
Here's a link http://example.com"
)
it "supports liking via email" do
expect { process(:like) }.to change(PostAction, :count)
end
it "properly renders email reply from Android 5 gmail client" do
expect(test_parse_body(fixture_file("emails/android_gmail.eml"))).
to eq(
"### this is a reply from Android 5 gmail
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over
the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown
fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
This is **bold** in Markdown.
This is a link to http://example.com"
)
end
it "properly renders email reply from Windows 8.1 Metro default mail client" do
expect(test_parse_body(fixture_file("emails/windows_8_metro.eml"))).
to eq(
"### reply from default mail client in Windows 8.1 Metro
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.
This is a **bold** word in Markdown
This is a link http://example.com"
)
end
it "properly renders email reply from MS Outlook client" do
expect(test_parse_body(fixture_file("emails/outlook.eml"))).to eq("Microsoft Outlook 2010")
end
it "converts back to UTF-8 at the end" do
result = test_parse_body(fixture_file("emails/big5.eml"))
expect(result.encoding).to eq(Encoding::UTF_8)
# should not throw
TextCleaner.normalize_whitespaces(
test_parse_body(fixture_file("emails/big5.eml"))
)
end
end
describe "posting replies" do
let(:reply_key) { raise "Override this in a lower describe block" }
let(:email_raw) { raise "Override this in a lower describe block" }
# ----
let(:to) { SiteSetting.reply_by_email_address.gsub("%{reply_key}", reply_key) }
let(:receiver) { Email::Receiver.new(email_raw) }
let(:post) { create_post }
let(:topic) { post.topic }
let(:posting_user) { post.user }
let(:replying_user_email) { 'jake@adventuretime.ooo' }
let(:replying_user) { Fabricate(:user, email: replying_user_email, trust_level: 2)}
let(:email_log) { EmailLog.new(reply_key: reply_key,
post: post,
post_id: post.id,
topic_id: post.topic_id,
email_type: 'user_posted',
user: replying_user,
user_id: replying_user.id,
to_address: replying_user_email
) }
before do
email_log.save
end
# === Success Posting ===
describe "valid_reply.eml" do
let!(:reply_key) { '59d8df8370b7e95c5a49fbf86aeb2c93' }
let!(:email_raw) { fill_email(fixture_file("emails/valid_reply.eml"), replying_user_email, to) }
it "creates a post with the correct content" do
start_count = topic.posts.count
receiver.process
expect(topic.posts.count).to eq(start_count + 1)
created_post = topic.posts.last
expect(created_post.via_email).to eq(true)
expect(created_post.cooked.strip).to eq(fixture_file("emails/valid_reply.cooked").strip)
end
end
describe "paragraphs.eml" do
let!(:reply_key) { '59d8df8370b7e95c5a49fbf86aeb2c93' }
let!(:email_raw) { fixture_file("emails/paragraphs.eml") }
it "cooks multiple paragraphs with traditional Markdown linebreaks" do
start_count = topic.posts.count
receiver.process
expect(topic.posts.count).to eq(start_count + 1)
expect(topic.posts.last.cooked.strip).to eq(fixture_file("emails/paragraphs.cooked").strip)
expect(topic.posts.last.cooked).not_to match(/<br/)
end
end
describe "attachment.eml" do
let!(:reply_key) { '636ca428858779856c226bb145ef4fad' }
let!(:email_raw) {
fixture_file("emails/attachment.eml")
.gsub("TO", "reply+#{reply_key}@appmail.adventuretime.ooo")
.gsub("FROM", replying_user_email)
}
let(:upload_sha) { '04df605be528d03876685c52166d4b063aabb78a' }
it "creates a post with an attachment" do
Upload.stubs(:fix_image_orientation)
ImageOptim.any_instance.stubs(:optimize_image!)
start_count = topic.posts.count
Upload.find_by(sha1: upload_sha).try(:destroy)
receiver.process
expect(topic.posts.count).to eq(start_count + 1)
expect(topic.posts.last.cooked).to match(/<img src=['"](\/uploads\/default\/original\/.+\.png)['"] width=['"]289['"] height=['"]126['"]>/)
expect(Upload.find_by(sha1: upload_sha)).not_to eq(nil)
end
describe 'Liking via email' do
let!(:reply_key) { '636ca428858779856c226bb145ef4fad' }
let(:replied_user_like_params) { { user: replying_user, post: post, post_action_type_id: PostActionType.types[:like] } }
let(:replied_user_like) { PostAction.find_by(replied_user_like_params) }
describe "plus_one.eml" do
let!(:email_raw) {
fixture_file("emails/plus_one.eml")
.gsub("TO", "reply+#{reply_key}@appmail.adventuretime.ooo")
.gsub("FROM", replying_user_email)
}
it "adds a user like to the post" do
expect { receiver.process }.to change { PostAction.count }.by(1)
expect(replied_user_like).to be_present
end
it "does not create a duplicate like" do
PostAction.create(replied_user_like_params)
before_count = PostAction.count
expect { receiver.process }.to raise_error(Email::Receiver::InvalidPostAction)
expect(PostAction.count).to eq before_count
expect(replied_user_like).to be_present
end
it "does not allow unauthorized happiness" do
post.trash!
before_count = PostAction.count
expect { receiver.process }.to raise_error(Email::Receiver::InvalidPostAction)
expect(PostAction.count).to eq before_count
expect(replied_user_like).to_not be_present
end
end
describe "like.eml" do
let!(:email_raw) {
fixture_file("emails/like.eml")
.gsub("TO", "reply+#{reply_key}@appmail.adventuretime.ooo")
.gsub("FROM", replying_user_email)
}
it 'adds a user like to the post' do
expect { receiver.process }.to change { PostAction.count }.by(1)
expect(replied_user_like).to be_present
end
end
end
end
# === Failure Conditions ===
describe "too_short.eml" do
let!(:reply_key) { '636ca428858779856c226bb145ef4fad' }
let!(:email_raw) {
fixture_file("emails/too_short.eml")
.gsub("TO", "reply+#{reply_key}@appmail.adventuretime.ooo")
.gsub("FROM", replying_user_email)
.gsub("SUBJECT", "re: [Discourse Meta] eviltrout posted in 'Adventure Time Sux'")
}
it "raises an InvalidPost error" do
SiteSetting.min_post_length = 5
expect { receiver.process }.to raise_error(Email::Receiver::InvalidPost)
end
end
describe "too_many_mentions.eml" do
let!(:reply_key) { '636ca428858779856c226bb145ef4fad' }
let!(:email_raw) { fixture_file("emails/too_many_mentions.eml") }
it "raises an InvalidPost error" do
SiteSetting.max_mentions_per_post = 10
(1..11).each do |i|
Fabricate(:user, username: "user#{i}").save
end
expect { receiver.process }.to raise_error(Email::Receiver::InvalidPost)
end
end
describe "auto response email replies should not be accepted" do
let!(:reply_key) { '636ca428858779856c226bb145ef4fad' }
let!(:email_raw) { fixture_file("emails/auto_reply.eml") }
it "raises a AutoGeneratedEmailError" do
expect { receiver.process }.to raise_error(Email::Receiver::AutoGeneratedEmailError)
end
it "ensures posts aren't dated in the future" do
expect { process(:from_the_future) }.to change { topic.posts.count }
expect(topic.posts.last.created_at).to be_within(1.minute).of(DateTime.now)
end
end
describe "posting reply to a closed topic" do
let(:reply_key) { raise "Override this in a lower describe block" }
let(:email_raw) { raise "Override this in a lower describe block" }
let(:to) { SiteSetting.reply_by_email_address.gsub("%{reply_key}", reply_key) }
let(:receiver) { Email::Receiver.new(email_raw) }
let(:topic) { Fabricate(:topic, closed: true) }
let(:post) { Fabricate(:post, topic: topic, post_number: 1) }
let(:replying_user_email) { 'jake@adventuretime.ooo' }
let(:replying_user) { Fabricate(:user, email: replying_user_email, trust_level: 2) }
let(:email_log) { EmailLog.new(reply_key: reply_key,
post: post,
post_id: post.id,
topic_id: topic.id,
email_type: 'user_posted',
user: replying_user,
user_id: replying_user.id,
to_address: replying_user_email
) }
context "new message to a group" do
before do
email_log.save
let!(:group) { Fabricate(:group, incoming_email: "team@bar.com") }
it "handles encoded display names" do
expect { process(:encoded_display_name) }.to change(Topic, :count)
topic = Topic.last
expect(topic.private_message?).to eq(true)
expect(topic.allowed_groups).to include(group)
user = topic.user
expect(user.staged).to eq(true)
expect(user.username).to eq("random_name")
expect(user.name).to eq("Случайная Имя")
end
describe "should not create post" do
let!(:reply_key) { '59d8df8370b7e95c5a49fbf86aeb2c93' }
let!(:email_raw) { fill_email(fixture_file("emails/valid_reply.eml"), replying_user_email, to) }
it "raises a TopicClosedError" do
expect { receiver.process }.to raise_error(Email::Receiver::TopicClosedError)
end
end
end
describe "posting reply to a deleted topic" do
let(:reply_key) { raise "Override this in a lower describe block" }
let(:email_raw) { raise "Override this in a lower describe block" }
let(:to) { SiteSetting.reply_by_email_address.gsub("%{reply_key}", reply_key) }
let(:receiver) { Email::Receiver.new(email_raw) }
let(:deleted_topic) { Fabricate(:deleted_topic) }
let(:post) { Fabricate(:post, topic: deleted_topic, post_number: 1) }
let(:replying_user_email) { 'jake@adventuretime.ooo' }
let(:replying_user) { Fabricate(:user, email: replying_user_email, trust_level: 2) }
let(:email_log) { EmailLog.new(reply_key: reply_key,
post: post,
post_id: post.id,
topic_id: deleted_topic.id,
email_type: 'user_posted',
user: replying_user,
user_id: replying_user.id,
to_address: replying_user_email
) }
before do
email_log.save
end
describe "should not create post" do
let!(:reply_key) { '59d8df8370b7e95c5a49fbf86aeb2c93' }
let!(:email_raw) { fill_email(fixture_file("emails/valid_reply.eml"), replying_user_email, to) }
it "raises a TopicNotFoundError" do
expect { receiver.process }.to raise_error(Email::Receiver::TopicNotFoundError)
end
end
end
describe "posting reply as a inactive user" do
let(:reply_key) { raise "Override this in a lower describe block" }
let(:email_raw) { raise "Override this in a lower describe block" }
let(:to) { SiteSetting.reply_by_email_address.gsub("%{reply_key}", reply_key) }
let(:receiver) { Email::Receiver.new(email_raw) }
let(:topic) { Fabricate(:topic) }
let(:post) { Fabricate(:post, topic: topic, post_number: 1) }
let(:replying_user_email) { 'jake@adventuretime.ooo' }
let(:replying_user) { Fabricate(:user, email: replying_user_email, trust_level: 2, active: false) }
let(:email_log) { EmailLog.new(reply_key: reply_key,
post: post,
post_id: post.id,
topic_id: topic.id,
email_type: 'user_posted',
user: replying_user,
user_id: replying_user.id,
to_address: replying_user_email
) }
before do
email_log.save
end
describe "should not create post" do
let!(:reply_key) { '59d8df8370b7e95c5a49fbf86aeb2c93' }
let!(:email_raw) { fill_email(fixture_file("emails/valid_reply.eml"), replying_user_email, to) }
it "raises a InactiveUserError" do
expect { receiver.process }.to raise_error(Email::Receiver::InactiveUserError)
end
end
end
describe "posting a new topic in a category" do
let(:category_destination) { raise "Override this in a lower describe block" }
let(:email_raw) { raise "Override this in a lower describe block" }
let(:allow_strangers) { false }
# ----
let(:receiver) { Email::Receiver.new(email_raw) }
let(:user_email) { 'jake@adventuretime.ooo' }
let(:user) { Fabricate(:user, email: user_email, trust_level: 2)}
let(:category) { Fabricate(:category, email_in: category_destination, email_in_allow_strangers: allow_strangers) }
before do
SiteSetting.email_in = true
user.save
category.save
end
describe "too_short.eml" do
let!(:category_destination) { 'incoming+amazing@appmail.adventuretime.ooo' }
let(:email_raw) {
fixture_file("emails/too_short.eml")
.gsub("TO", category_destination)
.gsub("FROM", user_email)
.gsub("SUBJECT", "A long subject that passes the checks")
}
it "does not create a topic if the post fails" do
before_topic_count = Topic.count
expect { receiver.process }.to raise_error(Email::Receiver::InvalidPost)
expect(Topic.count).to eq(before_topic_count)
end
it "invites everyone in the chain" do
expect { process(:cc) }.to change(Topic, :count)
emails = Topic.last.allowed_users.pluck(:email)
expect(emails.size).to eq(5)
expect(emails).to include("someone@else.com", "discourse@bar.com", "team@bar.com", "wat@bar.com", "42@bar.com")
end
end
def process_email(opts)
incoming_email = fixture_file("emails/valid_incoming.eml")
email = fill_email(incoming_email, opts[:from], opts[:to], opts[:body], opts[:subject], opts[:cc])
Email::Receiver.new(email).process
end
context "new topic in a category" do
describe "with a valid email" do
let(:reply_key) { "59d8df8370b7e95c5a49fbf86aeb2c93" }
let(:to) { SiteSetting.reply_by_email_address.gsub("%{reply_key}", reply_key) }
let(:user_email) { "test@test.com" }
let(:user) { Fabricate(:user, email: user_email, trust_level: 2)}
let(:post) { create_post(user: user) }
let(:valid_reply) {
reply = fixture_file("emails/valid_reply.eml")
fill_email(reply, user.email, to)
}
let(:receiver) { Email::Receiver.new(valid_reply) }
let(:email_log) { EmailLog.new(reply_key: reply_key,
post_id: post.id,
topic_id: post.topic_id,
user_id: post.user_id,
post: post,
user: user,
email_type: 'test',
to_address: user.email
) }
let(:reply_body) {
"I could not disagree more. I am obviously biased but adventure time is the
greatest show ever created. Everyone should watch it.
- Jake out" }
describe "with an email log" do
it "extracts data" do
expect { receiver.process }.to raise_error(Email::Receiver::EmailLogNotFound)
email_log.save!
receiver.process
expect(receiver.body).to eq(reply_body)
expect(receiver.email_log).to eq(email_log)
end
let!(:category) { Fabricate(:category, email_in: "category@bar.com", email_in_allow_strangers: false) }
it "raises a StrangersNotAllowedError when 'email_in_allow_strangers' is disabled" do
expect { process(:stranger_not_allowed) }.to raise_error(Email::Receiver::StrangersNotAllowedError)
end
end
describe "with a valid email from a different user" do
let(:reply_key) { SecureRandom.hex(16) }
let(:to) { SiteSetting.reply_by_email_address.gsub("%{reply_key}", reply_key) }
let(:user) { Fabricate(:user, email: "test@test.com", trust_level: 2)}
let(:post) { create_post(user: user) }
let!(:email_log) { EmailLog.create(reply_key: reply_key,
post_id: post.id,
topic_id: post.topic_id,
user_id: post.user_id,
post: post,
user: user,
email_type: 'test',
to_address: user.email) }
it "raises ReplyUserNotFoundError when user doesn't exist" do
reply = fill_email(fixture_file("emails/valid_reply.eml"), "unknown@user.com", to)
receiver = Email::Receiver.new(reply)
expect { receiver.process }.to raise_error(Email::Receiver::ReplyUserNotFoundError)
it "raises an InsufficientTrustLevelError when user's trust level isn't enough" do
SiteSetting.email_in_min_trust = 4
Fabricate(:user, email: "insufficient@bar.com", trust_level: 3)
expect { process(:insufficient_trust_level) }.to raise_error(Email::Receiver::InsufficientTrustLevelError)
end
it "raises ReplyUserNotMatchingError when user is not matching the reply key" do
another_user = Fabricate(:user, email: "existing@user.com")
reply = fill_email(fixture_file("emails/valid_reply.eml"), another_user.email, to)
receiver = Email::Receiver.new(reply)
expect { receiver.process }.to raise_error(Email::Receiver::ReplyUserNotMatchingError)
end
end
it "raises an InvalidAccess when the user is part of a readonly group" do
user = Fabricate(:user, email: "readonly@bar.com", trust_level: SiteSetting.email_in_min_trust)
group = Fabricate(:group)
describe "processes an email to a category" do
let(:to) { "some@email.com" }
group.add(user)
group.save
before do
SiteSetting.email_in = true
SiteSetting.email_in_min_trust = TrustLevel[4].to_s
end
it "correctly can target categories" do
Fabricate(:category, email_in_allow_strangers: false, email_in: to)
# no email in for user
expect{
process_email(from: "cobb@dob.com", to: "invalid@address.com")
}.to raise_error(Email::Receiver::BadDestinationAddress)
# valid target invalid user
expect{
process_email(from: "cobb@dob.com", to: to)
}.to raise_error(Email::Receiver::UserNotFoundError)
# untrusted
user = Fabricate(:user)
expect{
process_email(from: user.email, to: to)
}.to raise_error(Email::Receiver::UserNotSufficientTrustLevelError)
# trusted
user.trust_level = 4
user.save
process_email(from: user.email, to: to)
expect(user.posts.count).to eq(1)
# email too short
message = nil
begin
process_email(from: user.email, to: to, body: "x", subject: "this is my new topic title")
rescue Email::Receiver::InvalidPost => e
message = e.message
end
expect(e.message).to include("too short")
end
it "blocks user in restricted group from creating topic" do
to = "some@email.com"
restricted_user = Fabricate(:user, trust_level: 4)
restricted_group = Fabricate(:group)
restricted_group.add(restricted_user)
restricted_group.save
category = Fabricate(:category, email_in_allow_strangers: false, email_in: to)
category.set_permissions(restricted_group => :readonly)
category.set_permissions(group => :readonly)
category.save
expect{
process_email(from: restricted_user.email, to: to)
}.to raise_error(Discourse::InvalidAccess)
expect { process(:readonly) }.to raise_error(Discourse::InvalidAccess)
end
end
describe "processes an unknown email sender to category" do
let(:email_in) { "bob@bob.com" }
let(:user_email) { "#{SecureRandom.hex(32)}@foobar.com" }
let(:body) { "This is a new topic created\n\ninside a category ! :)" }
before do
SiteSetting.email_in = true
SiteSetting.allow_staged_accounts = true
end
it "rejects anon email" do
Fabricate(:category, email_in_allow_strangers: false, email_in: email_in)
expect {
process_email(from: user_email, to: email_in, body: body)
}.to raise_error(Email::Receiver::UserNotFoundError)
end
it "creates a topic for matching category" do
Fabricate(:category, email_in_allow_strangers: true, email_in: email_in)
process_email(from: user_email, to: email_in, body: body)
staged_account = User.find_by_email(user_email)
expect(staged_account).to be
expect(staged_account.staged).to be(true)
expect(staged_account.posts.order(id: :desc).limit(1).pluck(:raw).first).to eq(body)
end
end
describe "processes an unknown email sender to group" do
let(:incoming_email) { "foo@bar.com" }
let(:user_email) { "#{SecureRandom.hex(32)}@foobar.com" }
let(:body) { "This is a message to\n\na group ;)" }
before do
SiteSetting.email_in = true
SiteSetting.allow_staged_accounts = true
end
it "creates a message for matching group" do
Fabricate(:group, incoming_email: incoming_email)
process_email(from: user_email, to: incoming_email, body: body)
staged_account = User.find_by_email(user_email)
expect(staged_account).to be
expect(staged_account.name).to eq("Jake the Dog")
expect(staged_account.staged).to be(true)
post = staged_account.posts.order(id: :desc).first
expect(post).to be
expect(post.raw).to eq(body)
expect(post.topic.private_message?).to eq(true)
end
end
describe "supports incoming mail in CC fields" do
let(:incoming_email) { "foo@bar.com" }
let(:user_email) { "#{SecureRandom.hex(32)}@foobar.com" }
let(:body) { "This is a message to\n\na group via CC ;)" }
before do
SiteSetting.email_in = true
SiteSetting.allow_staged_accounts = true
end
it "creates a message for matching group" do
Fabricate(:group, incoming_email: incoming_email)
process_email(from: user_email, to: "some@email.com", body: body, cc: incoming_email)
staged_account = User.find_by_email(user_email)
expect(staged_account).to be
expect(staged_account.staged).to be(true)
post = staged_account.posts.order(id: :desc).first
expect(post).to be
expect(post.raw).to eq(body)
expect(post.topic.private_message?).to eq(true)
it "works" do
Fabricate(:user, email: "sufficient@bar.com", trust_level: SiteSetting.email_in_min_trust)
expect { process(:sufficient_trust_level) }.to change(Topic, :count)
end
end

View file

@ -1,177 +0,0 @@
Delivered-To: reply@discourse.org
Return-Path: <walter.white@googlemail.com>
MIME-Version: 1.0
In-Reply-To: <topic/22638/86406@meta.discourse.org>
References: <topic/22638@meta.discourse.org>
<topic/22638/86406@meta.discourse.org>
Date: Fri, 28 Nov 2014 12:53:21 -0800
Subject: Re: [Discourse Meta] [Lounge] Testing default email replies
From: Walter White <walter.white@googlemail.com>
To: Discourse Meta <reply@discourse.org>
Content-Type: multipart/alternative; boundary=089e0149cfa485c6630508f173df
--089e0149cfa485c6630508f173df
Content-Type: text/plain; charset=UTF-8
### this is a reply from Android 5 gmail
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over
the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown
fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
This is **bold** in Markdown.
This is a link to http://example.com
On Nov 28, 2014 12:36 PM, "Arpit Jalan" <info@discourse.org> wrote:
> techAPJ <https://meta.discourse.org/users/techapj>
> November 28
>
> Test reply.
>
> First paragraph.
>
> Second paragraph.
>
> To respond, reply to this email or visit
> https://meta.discourse.org/t/testing-default-email-replies/22638/3 in
> your browser.
> ------------------------------
> Previous Replies codinghorror
> <https://meta.discourse.org/users/codinghorror>
> November 28
>
> We're testing the latest GitHub email processing library which we are
> integrating now.
>
> https://github.com/github/email_reply_parser
>
> Go ahead and reply to this topic and I'll reply from various email clients
> for testing.
> ------------------------------
>
> To respond, reply to this email or visit
> https://meta.discourse.org/t/testing-default-email-replies/22638/3 in
> your browser.
>
> To unsubscribe from these emails, visit your user preferences
> <https://meta.discourse.org/my/preferences>.
>
--089e0149cfa485c6630508f173df
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<p dir=3D"ltr">### this is a reply from Android 5 gmail</p>
<p dir=3D"ltr">The quick brown fox jumps over the lazy dog. The quick brown=
fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. =
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over=
the lazy dog. The quick brown fox jumps over the lazy dog. </p>
<p dir=3D"ltr">This is **bold** in Markdown.</p>
<p dir=3D"ltr">This is a link to <a href=3D"http://example.com">http://exam=
ple.com</a></p>
<div class=3D"gmail_quote">On Nov 28, 2014 12:36 PM, &quot;Arpit Jalan&quot=
; &lt;<a href=3D"mailto:info@discourse.org">info@discourse.org</a>&gt; wrot=
e:<br type=3D"attribution"><blockquote class=3D"gmail_quote" style=3D"margi=
n:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div>
<table style=3D"margin-bottom:25px" cellspacing=3D"0" cellpadding=3D"0" bor=
der=3D"0">
<tbody>
<tr>
<td style=3D"vertical-align:top;width:55px">
<img src=3D"https://meta-discourse.global.ssl.fastly.net/user_avata=
r/meta.discourse.org/techapj/45/3281.png" title=3D"techAPJ" style=3D"max-wi=
dth:100%" width=3D"45" height=3D"45">
</td>
<td>
<a href=3D"https://meta.discourse.org/users/techapj" style=3D"text-=
decoration:none;font-weight:bold;color:#006699;font-size:13px;font-family:&=
#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;color:#3b5998;text-d=
ecoration:none;font-weight:bold" target=3D"_blank">techAPJ</a><br>
<span style=3D"text-align:right;color:#999999;padding-right:5px;fon=
t-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;font-size:=
11px">November 28</span>
</td>
</tr>
<tr>
<td style=3D"padding-top:5px" colspan=3D"2">
<p style=3D"margin-top:0;border:0">Test reply.</p>
<p style=3D"margin-top:0;border:0">First paragraph.</p>
<p style=3D"margin-top:0;border:0">Second paragraph.</p>
</td>
</tr>
</tbody>
</table>
<div style=3D"color:#666">
<p>To respond, reply to this email or visit <a href=3D"https://meta.dis=
course.org/t/testing-default-email-replies/22638/3" style=3D"text-decoratio=
n:none;font-weight:bold;color:#006699;color:#666" target=3D"_blank">https:/=
/meta.discourse.org/t/testing-default-email-replies/22638/3</a> in your bro=
wser.</p>
</div>
<hr style=3D"background-color:#ddd;min-height:1px;border:1px;background-c=
olor:#ddd;min-height:1px;border:1px">
<h4>Previous Replies</h4>
<table style=3D"margin-bottom:25px" cellspacing=3D"0" cellpadding=3D"0" b=
order=3D"0">
<tbody>
<tr>
<td style=3D"vertical-align:top;width:55px">
<img src=3D"https://meta-discourse.global.ssl.fastly.net/user_avata=
r/meta.discourse.org/codinghorror/45/5297.png" title=3D"codinghorror" style=
=3D"max-width:100%" width=3D"45" height=3D"45">
</td>
<td>
<a href=3D"https://meta.discourse.org/users/codinghorror" style=3D"=
text-decoration:none;font-weight:bold;color:#006699;font-size:13px;font-fam=
ily:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;color:#3b5998;t=
ext-decoration:none;font-weight:bold" target=3D"_blank">codinghorror</a><br=
>
<span style=3D"text-align:right;color:#999999;padding-right:5px;fon=
t-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;font-size:=
11px">November 28</span>
</td>
</tr>
<tr>
<td style=3D"padding-top:5px" colspan=3D"2">
<p style=3D"margin-top:0;border:0">We&#39;re testing the latest GitHub emai=
l processing library which we are integrating now.</p>
<p style=3D"margin-top:0;border:0"><a href=3D"https://github.com/github/ema=
il_reply_parser" style=3D"text-decoration:none;font-weight:bold;color:#0066=
99" target=3D"_blank">https://github.com/github/email_reply_parser</a></p>
<p style=3D"margin-top:0;border:0">Go ahead and reply to this topic and I&#=
39;ll reply from various email clients for testing.</p>
</td>
</tr>
</tbody>
</table>
<hr style=3D"background-color:#ddd;min-height:1px;border:1px;background-col=
or:#ddd;min-height:1px;border:1px">
<div style=3D"color:#666">
<p>To respond, reply to this email or visit <a href=3D"https://meta.discour=
se.org/t/testing-default-email-replies/22638/3" style=3D"text-decoration:no=
ne;font-weight:bold;color:#006699;color:#666" target=3D"_blank">https://met=
a.discourse.org/t/testing-default-email-replies/22638/3</a> in your browser=
.</p>
</div>
<div style=3D"color:#666">
<p>To unsubscribe from these emails, visit your <a href=3D"https://meta.dis=
course.org/my/preferences" style=3D"text-decoration:none;font-weight:bold;c=
olor:#006699;color:#666" target=3D"_blank">user preferences</a>.</p>
</div>
</div>
</blockquote></div>
--089e0149cfa485c6630508f173df--

View file

@ -1,351 +0,0 @@
Message-ID: <51C22E52.1030509@darthvader.ca>
Date: Wed, 19 Jun 2013 18:18:58 -0400
From: Anakin Skywalker <FROM>
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130510 Thunderbird/17.0.6
MIME-Version: 1.0
To: Han Solo via Death Star <TO>
Subject: Re: [Death Star] [PM] re: Regarding your post in "Site Customization
not working"
References: <51d23d33f41fb_5f4e4b35d7d60798@xwing.mail>
In-Reply-To: <51d23d33f41fb_5f4e4b35d7d60798@xwing.mail>
Content-Type: multipart/mixed; boundary=047d7b45041e19c68004eb9f3de8
--047d7b45041e19c68004eb9f3de8
Content-Type: multipart/alternative; boundary=047d7b45041e19c67b04eb9f3de6
--047d7b45041e19c67b04eb9f3de6
Content-Type: text/plain; charset=ISO-8859-1
here is an image attachment
On Tue, Nov 19, 2013 at 5:11 PM, Neil <info@discourse.org> wrote:
> Neil <http://meta.discourse.org/users/neil>
> November 19
>
> Actually, deleting a spammer does what it's supposed to. It does mark the
> topic as deleted.
>
> That topic has id 11002, and you're right that the user was deleted.
>
> @eviltrout <http://users/eviltrout> Any idea why it showed up in
> suggested topics?
>
> To respond, reply to this email or visit
> http://meta.discourse.org/t/spam-post-pops-back-up-in-suggested-topics/11005/5in your browser.
> ------------------------------
> Previous Replies Neil <http://meta.discourse.org/users/neil>
> November 19
>
> Looks like a bug when deleting a spammer. I'll look at it.
> riking <http://meta.discourse.org/users/riking>
> November 19
>
> codinghorror:
>
> I can't even find that topic by name.
>
> In that case, I'm fairly certain someone used the 'Delete Spammer'
> function on the user, which would explain your inability to find it - it's
> gone.
>
> I'm raising this because, well, it's gone and shouldn't be showing up. And
> even if it was hanging around, it should be invisible to me, and not
> showing up in Suggested Topics.
> codinghorror <http://meta.discourse.org/users/codinghorror>
> November 19
>
> Hmm, that's interesting -- can you have a look @eviltrout<http://users/eviltrout>?
> I can't even find that topic by name.
> riking <http://meta.discourse.org/users/riking>
> November 19
>
> I'm one of the users who flagged this particular spam post, and it was
> promptly deleted/hidden, but it just popped up in the Suggested Topics box:
>
> Pasted image1125x220 27.7 KB
> <//cdn.discourse.org/uploads/meta_discourse/2158/50b8b49557cb249e.png>
>
> We may want to recheck the suppression on these.
> ------------------------------
>
> To respond, reply to this email or visit
> http://meta.discourse.org/t/spam-post-pops-back-up-in-suggested-topics/11005/5in your browser.
>
> To unsubscribe from these emails, visit your user preferences<http://meta.discourse.org/user_preferences>
> .
>
--047d7b45041e19c67b04eb9f3de6
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">here is an image attachment</div><div class=3D"gmail_extra=
"><br><br><div class=3D"gmail_quote">On Tue, Nov 19, 2013 at 5:11 PM, Neil =
<span dir=3D"ltr">&lt;<a href=3D"mailto:info@discourse.org" target=3D"_blan=
k">info@discourse.org</a>&gt;</span> wrote:<br>
<blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p=
x #ccc solid;padding-left:1ex"><div>
<table style=3D"margin-bottom:25px;max-width:761px" cellspacing=3D"0" cellp=
adding=3D"0" border=3D"0"><tbody>
<tr>
<td style=3D"vertical-align:top;width:55px">
<img src=3D"http://www.gravatar.com/avatar/42776c4982dff1fa45ee8248=
532f8ad0.png?s=3D45&amp;r=3Dpg&amp;d=3Didenticon" title=3D"Neil" style=3D"m=
ax-width:694px" width=3D"45" height=3D"45">
</td>
<td>
<a href=3D"http://meta.discourse.org/users/neil" style=3D"font-size=
:13px;font-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;c=
olor:#3b5998;text-decoration:none;font-weight:bold" target=3D"_blank">Neil<=
/a><br>
<span style=3D"text-align:right;color:#999999;padding-right:5px;font-family=
:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;font-size:11px">No=
vember 19</span>
</td>
</tr>
<tr>
<td style=3D"padding-top:5px" colspan=3D"2">
<p style=3D"margin-top:0">Actually, deleting a spammer does what it&#39;s s=
upposed to. It does mark the topic as deleted.</p>
<p style=3D"margin-top:0">That topic has id 11002, and you&#39;re right tha=
t the user was deleted.</p>
<p style=3D"margin-top:0"><a href=3D"http://users/eviltrout" target=3D"_bla=
nk">@eviltrout</a> Any idea why it showed up in suggested topics? </p>
</td>
</tr>
</tbody></table>
<div style=3D"color:#666">
<p>To respond, reply to this email or visit <a href=3D"http://meta.disc=
ourse.org/t/spam-post-pops-back-up-in-suggested-topics/11005/5" style=3D"co=
lor:#666" target=3D"_blank">http://meta.discourse.org/t/spam-post-pops-back=
-up-in-suggested-topics/11005/5</a> in your browser.</p>
</div>
<hr style=3D"background-color:#ddd;min-height:1px;border:1px">
<h4>Previous Replies</h4>
<table style=3D"margin-bottom:25px;max-width:761px" cellspacing=3D"0" cel=
lpadding=3D"0" border=3D"0"><tbody>
<tr>
<td style=3D"vertical-align:top;width:55px">
<img src=3D"http://www.gravatar.com/avatar/42776c4982dff1fa45ee8248=
532f8ad0.png?s=3D45&amp;r=3Dpg&amp;d=3Didenticon" title=3D"Neil" style=3D"m=
ax-width:694px" width=3D"45" height=3D"45">
</td>
<td>
<a href=3D"http://meta.discourse.org/users/neil" style=3D"font-size=
:13px;font-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;c=
olor:#3b5998;text-decoration:none;font-weight:bold" target=3D"_blank">Neil<=
/a><br>
<span style=3D"text-align:right;color:#999999;padding-right:5px;font-family=
:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;font-size:11px">No=
vember 19</span>
</td>
</tr>
<tr>
<td style=3D"padding-top:5px" colspan=3D"2"><p style=3D"margin-top:0">Looks=
like a bug when deleting a spammer. I&#39;ll look at it.</p></td>
</tr>
</tbody></table>
<table style=3D"margin-bottom:25px;max-width:761px" cellspacing=3D"0" cellp=
adding=3D"0" border=3D"0"><tbody>
<tr>
<td style=3D"vertical-align:top;width:55px">
<img src=3D"http://www.gravatar.com/avatar/5120fc4e345db0d1a9648882=
72073819.png?s=3D45&amp;r=3Dpg&amp;d=3Didenticon" title=3D"riking" style=3D=
"max-width:694px" width=3D"45" height=3D"45">
</td>
<td>
<a href=3D"http://meta.discourse.org/users/riking" style=3D"font-si=
ze:13px;font-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif=
;color:#3b5998;text-decoration:none;font-weight:bold" target=3D"_blank">rik=
ing</a><br>
<span style=3D"text-align:right;color:#999999;padding-right:5px;font-family=
:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;font-size:11px">No=
vember 19</span>
</td>
</tr>
<tr>
<td style=3D"padding-top:5px" colspan=3D"2">
<p style=3D"margin-top:0"><u></u></p><div>
<div></div>
<img width=3D"20" height=3D"20" src=3D"http://www.gravatar.com/avatar/51d62=
3f33f8b83095db84ff35e15dbe8.png?s=3D40&amp;r=3Dpg&amp;d=3Didenticon" style=
=3D"max-width:694px">codinghorror:</div>
<blockquote><p style=3D"margin-top:0">I can&#39;t even find that topic by n=
ame.</p></blockquote><u></u><p></p>
<p style=3D"margin-top:0">In that case, I&#39;m fairly certain someone used=
the &#39;Delete Spammer&#39; function on the user, which would explain you=
r inability to find it - it&#39;s gone.</p>
<p style=3D"margin-top:0">I&#39;m raising this because, well, it&#39;s gone=
and shouldn&#39;t be showing up. And even if it was hanging around, it sho=
uld be invisible to me, and not showing up in Suggested Topics.</p>
</td>
</tr>
</tbody></table>
<table style=3D"margin-bottom:25px;max-width:761px" cellspacing=3D"0" cellp=
adding=3D"0" border=3D"0"><tbody>
<tr>
<td style=3D"vertical-align:top;width:55px">
<img src=3D"http://www.gravatar.com/avatar/51d623f33f8b83095db84ff3=
5e15dbe8.png?s=3D45&amp;r=3Dpg&amp;d=3Didenticon" title=3D"codinghorror" st=
yle=3D"max-width:694px" width=3D"45" height=3D"45">
</td>
<td>
<a href=3D"http://meta.discourse.org/users/codinghorror" style=3D"f=
ont-size:13px;font-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans=
-serif;color:#3b5998;text-decoration:none;font-weight:bold" target=3D"_blan=
k">codinghorror</a><br>
<span style=3D"text-align:right;color:#999999;padding-right:5px;font-family=
:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;font-size:11px">No=
vember 19</span>
</td>
</tr>
<tr>
<td style=3D"padding-top:5px" colspan=3D"2"><p style=3D"margin-top:0">Hmm, =
that&#39;s interesting -- can you have a look <a href=3D"http://users/evilt=
rout" target=3D"_blank">@eviltrout</a>? I can&#39;t even find that topic by=
name. </p>
</td>
</tr>
</tbody></table>
<table style=3D"margin-bottom:25px;max-width:761px" cellspacing=3D"0" cellp=
adding=3D"0" border=3D"0"><tbody>
<tr>
<td style=3D"vertical-align:top;width:55px">
<img src=3D"http://www.gravatar.com/avatar/5120fc4e345db0d1a9648882=
72073819.png?s=3D45&amp;r=3Dpg&amp;d=3Didenticon" title=3D"riking" style=3D=
"max-width:694px" width=3D"45" height=3D"45">
</td>
<td>
<a href=3D"http://meta.discourse.org/users/riking" style=3D"font-si=
ze:13px;font-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif=
;color:#3b5998;text-decoration:none;font-weight:bold" target=3D"_blank">rik=
ing</a><br>
<span style=3D"text-align:right;color:#999999;padding-right:5px;font-family=
:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;font-size:11px">No=
vember 19</span>
</td>
</tr>
<tr>
<td style=3D"padding-top:5px" colspan=3D"2">
<p style=3D"margin-top:0">I&#39;m one of the users who flagged this particu=
lar spam post, and it was promptly deleted/hidden, but it just popped up in=
the Suggested Topics box:</p>
<p style=3D"margin-top:0"></p>
<div><a href=3D"//cdn.discourse.org/uploads/meta_discourse/2158/50b8b49557c=
b249e.png" target=3D"_blank"><img src=3D"http://cdn.discourse.org/uploads/m=
eta_discourse/_optimized/ab1/c92/acd2c33402_584x134.png" width=3D"584" heig=
ht=3D"134" style=3D"max-width:694px"><div>
<span>Pasted image</span><span>1125x220 27.7 KB</span><span></span>
</div></a></div>
<p style=3D"margin-top:0">We may want to recheck the suppression on these.<=
/p>
</td>
</tr>
</tbody></table>
<hr style=3D"background-color:#ddd;min-height:1px;border:1px">
<div style=3D"color:#666">
<p>To respond, reply to this email or visit <a href=3D"http://meta.discours=
e.org/t/spam-post-pops-back-up-in-suggested-topics/11005/5" style=3D"color:=
#666" target=3D"_blank">http://meta.discourse.org/t/spam-post-pops-back-up-=
in-suggested-topics/11005/5</a> in your browser.</p>
</div>
<div style=3D"color:#666">
<p>To unsubscribe from these emails, visit your <a href=3D"http://meta.disc=
ourse.org/user_preferences" style=3D"color:#666" target=3D"_blank">user pre=
ferences</a>.</p>
</div>
</div></blockquote></div><br></div>
--047d7b45041e19c67b04eb9f3de6--
--047d7b45041e19c68004eb9f3de8
Content-Type: image/png; name="bricks.png"
Content-Disposition: attachment; filename="bricks.png"
Content-Transfer-Encoding: base64
X-Attachment-Id: f_ho8uteve0
iVBORw0KGgoAAAANSUhEUgAAASEAAAB+CAIAAADk0DDaAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ
bWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdp
bj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6
eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEz
NDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJo
dHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlw
dGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAv
IiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RS
ZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpD
cmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNl
SUQ9InhtcC5paWQ6MDYxQjcyOUUzMDM1MTFFM0JFRTFBOTQ1RUY4QUU4MDIiIHhtcE1NOkRvY3Vt
ZW50SUQ9InhtcC5kaWQ6MDYxQjcyOUYzMDM1MTFFM0JFRTFBOTQ1RUY4QUU4MDIiPiA8eG1wTU06
RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowNjFCNzI5QzMwMzUxMUUzQkVF
MUE5NDVFRjhBRTgwMiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowNjFCNzI5RDMwMzUxMUUz
QkVFMUE5NDVFRjhBRTgwMiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1w
bWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pm2fyz0AAAyISURBVHja7F2/i11FFL6rL12aBdlGRDCF
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
AAAAAElFTkSuQmCC
--047d7b45041e19c68004eb9f3de8--

View file

@ -0,0 +1,8 @@
Return-Path: <foo@bar.com>
From: Foo Bar <foo@bar.com>
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <3@foo.bar.mail>
Auto-Submitted: auto-generated
Mime-Version: 1.0
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

View file

@ -0,0 +1,8 @@
Return-Path: <foo@bar.com>
From: Foo Bar <foo@bar.com>
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <2@foo.bar.mail>
Precedence: list
Mime-Version: 1.0
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

View file

@ -1,21 +0,0 @@
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 <reply+59d8df8370b7e95c5a49fbf86aeb2c93@discourse.example.com>; Thu, 13 Jun 2013 17:03:50 -0400
Received: by mail-ie0-f180.google.com with SMTP id f4so21977375iea.25 for <reply+59d8df8370b7e95c5a49fbf86aeb2c93@discourse.example.com>; 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: reply+636ca428858779856c226bb145ef4fad@appmail.adventuretime.ooo
Message-ID: <CADkmRc+rNGAGGbV2iE5p918UVy4UyJqVcXRO2=otppgzduJSg@mail.gmail.com>
Subject: re: [Discourse Meta] eviltrout posted in 'Adventure Time Sux'
Mime-Version: 1.0
Content-Type: text/plain;
charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
Auto-Submitted: auto-generated
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
Test reply to Discourse email digest

View file

@ -0,0 +1,11 @@
Return-Path: <staged@bar.com>
From: Foo Bar <staged@bar.com>
To: wat@bar.com
Cc: foofoo@bar.com
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <9@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
Lorem ipsum dolor sit amet, consectetur adipiscing elit.

View file

@ -1,26 +0,0 @@
Delivered-To: discourse-reply+cd480e301683c9902891f15968bf07a5@discourse.org
Received: by 10.194.216.104 with SMTP id op8csp80593wjc;
Wed, 24 Jul 2013 07:59:14 -0700 (PDT)
Return-Path: <walter.white@googlemail.com>
References: <topic/5043@discourse.org> <51efeb9b36c34_66dc2dfce6811866@discourse.mail>
From: Walter White <walter.white@googlemail.com>
In-Reply-To: <51efeb9b36c34_66dc2dfce6811866@discourse.mail>
Mime-Version: 1.0 (1.0)
Date: Wed, 24 Jul 2013 15:59:10 +0100
Message-ID: <4597127794206131679@unknownmsgid>
Subject: Re: [Discourse] new reply to your post in 'Crystal Blue'
To: walter via Discourse <reply+cd480e301683c9902891f15968bf07a5@appmail.adventuretime.ooo>
Content-Type: multipart/alternative; boundary=20cf301cc47ada510404f040b262
--20cf301cc47ada510404f040b262
Content-Type: text/plain; charset=Big5
Content-Transfer-Encoding: base64
tv2hSafapFe5cbX4pEahSQ0K
--20cf301cc47ada510404f040b262
Content-Type: text/html; charset=Big5
Content-Transfer-Encoding: base64
PGRpdiBkaXI9Imx0ciI+tv2hSafapFe5cbX4pEahSTxicj48L2Rpdj4NCg==
--20cf301cc47ada510404f040b262--

View file

@ -1,160 +0,0 @@
Received: by 10.107.19.29 with SMTP id b29csp111716ioj;
Wed, 30 Jul 2014 17:52:05 -0700 (PDT)
X-Received: by 10.194.238.6 with SMTP id vg6mr11340975wjc.24.1406767925330;
Wed, 30 Jul 2014 17:52:05 -0700 (PDT)
Received: from localhost (localhost [127.0.0.1])
by bendel.debian.org (Postfix) with QMQP
id 18F5C417; Thu, 31 Jul 2014 00:52:04 +0000 (UTC)
Old-Return-Path: <vorlon@debian.org>
X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on bendel.debian.org
X-Spam-Level:
X-Spam-Status: No, score=-25.9 required=4.0 tests=FOURLA,LDOSUBSCRIBER,
LDO_WHITELIST,MURPHY_DEBIAN_MESSAGE,PGPSIGNATURE autolearn=unavailable
version=3.3.2
X-Original-To: lists-debian-ctte@bendel.debian.org
Delivered-To: lists-debian-ctte@bendel.debian.org
Received: from localhost (localhost [127.0.0.1])
by bendel.debian.org (Postfix) with ESMTP id CE6CDEE
for <lists-debian-ctte@bendel.debian.org>; Thu, 31 Jul 2014 00:51:52 +0000 (UTC)
X-Virus-Scanned: at lists.debian.org with policy bank en-lt
X-Amavis-Spam-Status: No, score=-11.9 tagged_above=-10000 required=5.3
tests=[BAYES_00=-2, FOURLA=0.1, LDO_WHITELIST=-5, PGPSIGNATURE=-5]
autolearn=ham
Received: from bendel.debian.org ([127.0.0.1])
by localhost (lists.debian.org [127.0.0.1]) (amavisd-new, port 2525)
with ESMTP id SB451DwGZCOe for <lists-debian-ctte@bendel.debian.org>;
Thu, 31 Jul 2014 00:51:47 +0000 (UTC)
X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_BL_NJABL=-1.5 CL_IP_EQ_HELO_IP=-2 (check from: .debian. - helo: .becquer.dodds. - helo-domain: .dodds.) FROM/MX_MATCHES_NOT_HELO(DOMAIN)=0; rate: -5
Received: from becquer.dodds.net (becquer.dodds.net [207.224.24.209])
by bendel.debian.org (Postfix) with ESMTP id 8E89A2B4
for <debian-ctte@lists.debian.org>; Thu, 31 Jul 2014 00:51:47 +0000 (UTC)
Received: from virgil.dodds.net (unknown [192.168.15.59])
by becquer.dodds.net (Postfix) with ESMTPA id 9B0A9256EB
for <debian-ctte@lists.debian.org>; Wed, 30 Jul 2014 17:51:19 -0700 (PDT)
Received: by virgil.dodds.net (Postfix, from userid 1000)
id 942FB60199; Wed, 30 Jul 2014 17:51:15 -0700 (PDT)
Date: Wed, 30 Jul 2014 17:51:15 -0700
From: Jake <jake@adventuretime.ooo>
To: incoming+amazing@appmail.adventuretime.ooo
Subject: Re: Next Debian CTTE IRC Meeting at date -d'Thu Jul 31 17:00:00 UTC
2014'
Message-ID: <20140731005115.GA19044@virgil.dodds.net>
Mail-Followup-To: debian-ctte@lists.debian.org
References: <20140730213924.GA12356@teltox.donarmstrong.com>
MIME-Version: 1.0
Content-Type: multipart/signed; micalg=pgp-sha256;
protocol="application/pgp-signature"; boundary="qMm9M+Fa2AknHoGS"
Content-Disposition: inline
In-Reply-To: <20140730213924.GA12356@teltox.donarmstrong.com>
User-Agent: Mutt/1.5.23 (2014-03-12)
X-Debian-Message: Signature check passed for Debian member
X-Rc-Virus: 2007-09-13_01
X-Rc-Spam: 2008-11-04_01
Resent-Message-ID: <c_LGA2C2wUK.A.URD.zMZ2TB@bendel>
Resent-From: debian-ctte@lists.debian.org
X-Mailing-List: <debian-ctte@lists.debian.org> archive/latest/4791
X-Loop: debian-ctte@lists.debian.org
List-Id: <debian-ctte.lists.debian.org>
List-Post: <mailto:debian-ctte@lists.debian.org>
List-Help: <mailto:debian-ctte-request@lists.debian.org?subject=help>
List-Subscribe: <mailto:debian-ctte-request@lists.debian.org?subject=subscribe>
List-Unsubscribe: <mailto:debian-ctte-request@lists.debian.org?subject=unsubscribe>
Precedence: list
Resent-Sender: debian-ctte-request@lists.debian.org
Resent-Date: Thu, 31 Jul 2014 00:52:04 +0000 (UTC)
--qMm9M+Fa2AknHoGS
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
On Wed, Jul 30, 2014 at 02:39:24PM -0700, Don Armstrong wrote:
> The next Debian CTTE IRC meeting is at=20
> date -d 'Thu Jul 31 17:00:00 UTC 2014' on irc.debian.org in
> #debian-ctte.
> The current meeting agenda is here, and more up-to-date ones may be
> found in the git repository.
> #startmeeting
> #topic Who is here?
> #topic Next Meeting?
> #topic #717076 Decide between libjpeg-turbo and libjpeg8 et al.
This has been voted on; should probably be removed from the agenda, someone
just needs to confirm the vote results and get it on the website. (AIUI the
archive has already begun moving on accordingly.)
> #topic #636783 constitution: super-majority bug
> #topic #636783 constitution: casting vote
> #topic #636783 constitution: minimum discussion period
> #topic #636783 constitution: TC member retirement/rollover
> #topic #636783 constitution: TC chair retirement/rollover
> #topic #681419 Depends: foo | foo-nonfree
> #topic #741573 menu systems and mime-support
> #topic #746715 init system fallout
Also voted and just needs to be confirmed.
> #topic #750135 Maintainer of aptitude package
>=20
> #topic #752400 Advice on util-linux
This has been closed by mutual agreement of the people involved and doesn't
require any action from the TC. Removed from the agenda.
There's also bug #744246, which was assigned to the TC at my request but
without any preamble so it may have escaped notice. However, that situation
has been evolving constructively among the related parties (apparently, an
informal comment from a member of the release team was mistaken for a
release team position, so that's now being revisited), so I don't believe
this is anything we need to put on the agenda for tomorrow despite being on
the open bug list.
--=20
Steve Langasek Give me a lever long enough and a Free OS
Debian Developer to set it on, and I can move the world.
Ubuntu Developer http://www.debian.org/
slangasek@ubuntu.com vorlon@debian.org
--qMm9M+Fa2AknHoGS
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: Digital signature
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQIcBAEBCAAGBQJT2ZMDAAoJEFaNMPMhshM9GLsP/244S3wtYZEeVgJWIdB5PE0A
sZVezEA692y++/0oVZVecwV67yBOyfSjPPetdAph2UDMRtfurwxfj2BkbOFA2+Y6
++MErbmC3V7IGpd/L/fFGdXgvMQT2MNBpw0fnMA7bLpNjCvoj+Hr1HXRUcWoJSlj
WmHWwWSTVRcHg8a3iWYJzY6XfLyEEgHlahrlKvJExsTx/9mc1qg7g8KGdnhzHFBl
ttdH2fxpAk/624dReCcw5RKmOLfZ1HsEl9XcVe1cb4K+MDaQiXmoEK5v3xaNz1tS
NK5v2D5gDs229zoxKzQnnzOPLHxqI5E0L9PpI/mu4T9z7H2bHR3U5BvhnT99t5uw
ydf2cZNGY0uFCV3Rvn07BfAIW5WSXhOfN/5IymRKmdhjsTiwZ/wFjFrK8tVjtERu
yeyA7RIYiblGCEKYIYLWSxhoXeEdmAdfp6EA2/IA1CpgMB+ZdSfaeMgFY7xosgmG
ax3NTnaKyhr1QEUJ2gjAwHnKjuGbRVDAinYrSvP0o8Bh9sAs2BN2negWBCZVwwkN
S9hWTjVqsBmpaPOt5SEDwDo9O9dfzkmaamDsxOuUEz9F7v5jYg0mxA/WbogGty9R
vOMKxdxRkzflL/CferVbkzL/EkZRDfWDp9SleZggrpz7miiNDbS7jdRzJ4EttmJ8
gHBAVrOzcnbIPOIkk9pw
=KXIu
-----END PGP SIGNATURE-----
--qMm9M+Fa2AknHoGS--
--
To UNSUBSCRIBE, email to debian-ctte-REQUEST@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmaster@lists.debian.org
Archive: https://lists.debian.org/20140731005115.GA19044@virgil.dodds.net

View file

@ -1,61 +0,0 @@
MIME-Version: 1.0
Received: by 10.64.14.41 with HTTP; Wed, 19 Jun 2013 06:29:41 -0700 (PDT)
In-Reply-To: <51c19490e928a_13442dd8ae892548@tree.mail>
References: <51c19490e928a_13442dd8ae892548@tree.mail>
Date: Wed, 19 Jun 2013 09:29:41 -0400
Delivered-To: finn@adventuretime.ooo
Message-ID: <CADkmRcL=2aPV7jOcs2i00QGZNwmjYj3qMaJTsKnB7DTP5sgyFQ@mail.gmail.com>
Subject: Re: [Adventure Time] jake mentioned you in 'peppermint butler is
missing'
From: Finn the Human <finn@adventuretime.ooo>
To: jake via Adventure Time <reply+96dcd9072ba9072d06226009d4223a6e@appmail.adventuretime.ooo>
Content-Type: multipart/alternative; boundary=001a11c206a073876a04df81d2a9
--001a11c206a073876a04df81d2a9
Content-Type: text/plain; charset=ISO-8859-1
I'll look into it, thanks!
On Wednesday, June 19, 2013, jake via Discourse wrote:
> jake mentioned you in 'peppermint butler is missing' on Adventure
> Time:
> ------------------------------
>
> yeah, just noticed this cc @jake
> ------------------------------
>
> Please visit this link to respond:
> http://adventuretime.ooo/t/peppermint-butler-is-missing/7628/2
>
> To unsubscribe from these emails, visit your user preferences
> <http://adventuretime.ooo/user_preferences>.
>
--001a11c206a073876a04df81d2a9
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
I&#39;ll look into it, thanks!<span></span><br><br>On Wednesday, June 19, 2=
013, jake via Adventure Time wrote:<br><blockquote class=3D"gmail_quote" st=
yle=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><p>sa=
m mentioned you in &#39;Duplicate message are shown in profile&#39; on Adve=
nture Time</p>
<hr><p>yeah, just noticed this cc <a href=3D"http://users/eviltrout" target=
=3D"_blank">@eviltrout</a> </p>
<hr><p>Please visit this link to respond: <a href=3D"http://adventuretime.oo=
o/t/duplicate-message-are-shown-in-profile/7628/2" target=3D"_blank">http=
://adventuretime.ooo/t/peppermint-butler-is-missing/7628/2</a></=
p>
<p>To unsubscribe from these emails, visit your <a href=3D"http://adventuret=
ime.ooo/user_preferences" target=3D"_blank">user preferences</a>.</p>
</blockquote>
--001a11c206a073876a04df81d2a9--

12
spec/fixtures/emails/cc.eml vendored Normal file
View file

@ -0,0 +1,12 @@
Return-Path: <discourse@bar.com>
From: Foo Bar <discourse@bar.com>
To: someone@else.com
CC: team@bar.com, wat@bar.com, 42@bar.com
Subject: The more, the merrier
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <30@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
It is more fun with more people.

10
spec/fixtures/emails/chinese_reply.eml vendored Normal file
View file

@ -0,0 +1,10 @@
Return-Path: <discourse@bar.com>
From: Foo Bar <discourse@bar.com>
To: reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <17@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain; charset=Big5
Content-Transfer-Encoding: base64
5oKo5aW977yBIOS9oOS7iuWkqeWlveWQl++8nw==

View file

@ -1,20 +0,0 @@
Delivered-To: discourse-reply+cd480e301683c9902891f15968bf07a5@discourse.org
Received: by 10.194.216.104 with SMTP id op8csp80593wjc;
Wed, 24 Jul 2013 07:59:14 -0700 (PDT)
Return-Path: <walter.white@googlemail.com>
References: <topic/5043@discourse.org> <51efeb9b36c34_66dc2dfce6811866@discourse.mail>
From: Walter White <walter.white@googlemail.com>
In-Reply-To: <51efeb9b36c34_66dc2dfce6811866@discourse.mail>
Mime-Version: 1.0 (1.0)
Date: Wed, 24 Jul 2013 15:59:10 +0100
Message-ID: <4597127794206131679@unknownmsgid>
Subject: Re: [Discourse] new reply to your post in 'Crystal Blue'
To: walter via Discourse <reply+cd480e301683c9902891f15968bf07a5@appmail.adventuretime.ooo>
Content-Type: multipart/alternative; boundary=001a11c20edc15a39304e2432790
Dit is een antwoord in het Nederlands.
Op 18 juli 2013 10:23 schreef Sander Datema het volgende:
Dit is de originele post.

View file

@ -1,21 +0,0 @@
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 <reply+59d8df8370b7e95c5a49fbf86aeb2c93@discourse.example.com>; Thu, 13 Jun 2013 17:03:50 -0400
Received: by mail-ie0-f180.google.com with SMTP id f4so21977375iea.25 for <reply+59d8df8370b7e95c5a49fbf86aeb2c93@discourse.example.com>; 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: reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo
Message-ID: <CADkmRc+rNGAGGbV2iE5p918UVy4UyJqVcXRO2=otppgzduJSg@mail.gmail.com>
Subject: re: [Discourse Meta] eviltrout posted in 'Adventure Time Sux'
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

View file

@ -0,0 +1,11 @@
Return-Path: <random.name@bar.ru>
From: =?UTF-8?B?0KHQu9GD0YfQsNC50L3QsNGP?= =?UTF-8?B?INCY0LzRjw==?= <random.name@bar.ru>
To: team@bar.com
Subject: I need help
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <29@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Будьте здоровы!

View file

@ -0,0 +1,10 @@
Return-Path: <discourse@bar.com>
From: Foo Bar <discourse@bar.com>
To: reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com
Date: Wed, 01 Jan 3000 00:00:00 +0100
Message-ID: <4@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
Back to the future!

View file

@ -1,181 +0,0 @@
Delivered-To: reply@discourse.org
Return-Path: <walter.white@googlemail.com>
MIME-Version: 1.0
In-Reply-To: <topic/22638/86406@meta.discourse.org>
References: <topic/22638@meta.discourse.org>
<topic/22638/86406@meta.discourse.org>
Date: Fri, 28 Nov 2014 12:36:49 -0800
Subject: Re: [Discourse Meta] [Lounge] Testing default email replies
From: Walter White <walter.white@googlemail.com>
To: Discourse Meta <reply@discourse.org>
Content-Type: multipart/alternative; boundary=001a11c2e04e6544f30508f138ba
--001a11c2e04e6544f30508f138ba
Content-Type: text/plain; charset=UTF-8
### This is a reply from standard GMail in Google Chrome.
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over
the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown
fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over
the lazy dog. The quick brown fox jumps over the lazy dog.
Here's some **bold** text in Markdown.
Here's a link http://example.com
On Fri, Nov 28, 2014 at 12:35 PM, Arpit Jalan <info@discourse.org> wrote:
> techAPJ <https://meta.discourse.org/users/techapj>
> November 28
>
> Test reply.
>
> First paragraph.
>
> Second paragraph.
>
> To respond, reply to this email or visit
> https://meta.discourse.org/t/testing-default-email-replies/22638/3 in
> your browser.
> ------------------------------
> Previous Replies codinghorror
> <https://meta.discourse.org/users/codinghorror>
> November 28
>
> We're testing the latest GitHub email processing library which we are
> integrating now.
>
> https://github.com/github/email_reply_parser
>
> Go ahead and reply to this topic and I'll reply from various email clients
> for testing.
> ------------------------------
>
> To respond, reply to this email or visit
> https://meta.discourse.org/t/testing-default-email-replies/22638/3 in
> your browser.
>
> To unsubscribe from these emails, visit your user preferences
> <https://meta.discourse.org/my/preferences>.
>
--001a11c2e04e6544f30508f138ba
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>### This is a reply from standard GMail in Google Chr=
ome.</div><div><br></div><div>The quick brown fox jumps over the lazy dog. =
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over=
the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown=
fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. =
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over=
the lazy dog.=C2=A0</div><div><br></div><div>Here&#39;s some **bold** text=
in Markdown.</div><div><br></div><div>Here&#39;s a link <a href=3D"http://=
example.com">http://example.com</a></div></div><div class=3D"gmail_extra"><=
br><div class=3D"gmail_quote">On Fri, Nov 28, 2014 at 12:35 PM, Arpit Jalan=
<span dir=3D"ltr">&lt;<a href=3D"mailto:info@discourse.org" target=3D"_bla=
nk">info@discourse.org</a>&gt;</span> wrote:<br><blockquote class=3D"gmail_=
quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1=
ex"><div>
<table style=3D"margin-bottom:25px" cellspacing=3D"0" cellpadding=3D"0" bor=
der=3D"0">
<tbody>
<tr>
<td style=3D"vertical-align:top;width:55px">
<img src=3D"https://meta-discourse.global.ssl.fastly.net/user_avata=
r/meta.discourse.org/techapj/45/3281.png" title=3D"techAPJ" style=3D"max-wi=
dth:100%" width=3D"45" height=3D"45">
</td>
<td>
<a href=3D"https://meta.discourse.org/users/techapj" style=3D"text-=
decoration:none;font-weight:bold;color:#006699;font-size:13px;font-family:&=
#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;color:#3b5998;text-d=
ecoration:none;font-weight:bold" target=3D"_blank">techAPJ</a><br>
<span style=3D"text-align:right;color:#999999;padding-right:5px;fon=
t-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;font-size:=
11px">November 28</span>
</td>
</tr>
<tr>
<td style=3D"padding-top:5px" colspan=3D"2">
<p style=3D"margin-top:0;border:0">Test reply.</p>
<p style=3D"margin-top:0;border:0">First paragraph.</p>
<p style=3D"margin-top:0;border:0">Second paragraph.</p>
</td>
</tr>
</tbody>
</table>
<div style=3D"color:#666">
<p>To respond, reply to this email or visit <a href=3D"https://meta.dis=
course.org/t/testing-default-email-replies/22638/3" style=3D"text-decoratio=
n:none;font-weight:bold;color:#006699;color:#666" target=3D"_blank">https:/=
/meta.discourse.org/t/testing-default-email-replies/22638/3</a> in your bro=
wser.</p>
</div>
<hr style=3D"background-color:#ddd;min-height:1px;border:1px;background-c=
olor:#ddd;min-height:1px;border:1px">
<h4>Previous Replies</h4>
<table style=3D"margin-bottom:25px" cellspacing=3D"0" cellpadding=3D"0" b=
order=3D"0">
<tbody>
<tr>
<td style=3D"vertical-align:top;width:55px">
<img src=3D"https://meta-discourse.global.ssl.fastly.net/user_avata=
r/meta.discourse.org/codinghorror/45/5297.png" title=3D"codinghorror" style=
=3D"max-width:100%" width=3D"45" height=3D"45">
</td>
<td>
<a href=3D"https://meta.discourse.org/users/codinghorror" style=3D"=
text-decoration:none;font-weight:bold;color:#006699;font-size:13px;font-fam=
ily:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;color:#3b5998;t=
ext-decoration:none;font-weight:bold" target=3D"_blank">codinghorror</a><br=
>
<span style=3D"text-align:right;color:#999999;padding-right:5px;fon=
t-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;font-size:=
11px">November 28</span>
</td>
</tr>
<tr>
<td style=3D"padding-top:5px" colspan=3D"2">
<p style=3D"margin-top:0;border:0">We&#39;re testing the latest GitHub emai=
l processing library which we are integrating now.</p>
<p style=3D"margin-top:0;border:0"><a href=3D"https://github.com/github/ema=
il_reply_parser" style=3D"text-decoration:none;font-weight:bold;color:#0066=
99" target=3D"_blank">https://github.com/github/email_reply_parser</a></p>
<p style=3D"margin-top:0;border:0">Go ahead and reply to this topic and I&#=
39;ll reply from various email clients for testing.</p>
</td>
</tr>
</tbody>
</table>
<hr style=3D"background-color:#ddd;min-height:1px;border:1px;background-col=
or:#ddd;min-height:1px;border:1px">
<div style=3D"color:#666">
<p>To respond, reply to this email or visit <a href=3D"https://meta.discour=
se.org/t/testing-default-email-replies/22638/3" style=3D"text-decoration:no=
ne;font-weight:bold;color:#006699;color:#666" target=3D"_blank">https://met=
a.discourse.org/t/testing-default-email-replies/22638/3</a> in your browser=
.</p>
</div>
<div style=3D"color:#666">
<p>To unsubscribe from these emails, visit your <a href=3D"https://meta.dis=
course.org/my/preferences" style=3D"text-decoration:none;font-weight:bold;c=
olor:#006699;color:#666" target=3D"_blank">user preferences</a>.</p>
</div>
</div>
</blockquote></div><br></div>
--001a11c2e04e6544f30508f138ba--

View file

@ -1,17 +0,0 @@
Delivered-To: discourse-reply+cd480e301683c9902891f15968bf07a5@discourse.org
Received: by 10.194.216.104 with SMTP id op8csp80593wjc;
Wed, 24 Jul 2013 07:59:14 -0700 (PDT)
Return-Path: <walter.white@googlemail.com>
References: <topic/5043@discourse.org> <51efeb9b36c34_66dc2dfce6811866@discourse.mail>
From: Walter White <walter.white@googlemail.com>
In-Reply-To: <51efeb9b36c34_66dc2dfce6811866@discourse.mail>
Mime-Version: 1.0 (1.0)
Date: Wed, 24 Jul 2013 15:59:10 +0100
Message-ID: <4597127794206131679@unknownmsgid>
Subject: Re: [Discourse] new reply to your post in 'Crystal Blue'
To: walter via Discourse <reply+cd480e301683c9902891f15968bf07a5@appmail.adventuretime.ooo>
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: base64
16nXnNeV150=

10
spec/fixtures/emails/hebrew_reply.eml vendored Normal file
View file

@ -0,0 +1,10 @@
Return-Path: <discourse@bar.com>
From: Foo Bar <discourse@bar.com>
To: reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <16@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: base64
16nXnNeV150hINee15Qg16nXnNeV157XmiDXlNeZ15XXnT8=

View file

@ -1,93 +0,0 @@
Delivered-To: walter@breakingbad.com
Received: by 10.64.13.41 with SMTP id m9csp29769iec;
Thu, 20 Jun 2013 08:53:22 -0700 (PDT)
X-Received: by 10.252.23.9 with SMTP id p9mr4055675lag.4.1371743601980;
Thu, 20 Jun 2013 08:53:21 -0700 (PDT)
Received: from mail-la0-x229.google.com (mail-la0-x229.google.com [2a00:1450:4010:c03::229])
by mx.google.com with ESMTPS id u4si430203lae.48.2013.06.20.08.53.20
for <walter@breakingbad.com>
(version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128);
Thu, 20 Jun 2013 08:53:21 -0700 (PDT)
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=google.com; s=20120113;
h=x-forwarded-to:x-forwarded-for:delivered-to:x-return-path
:content-type:mime-version:content-transfer-encoding:x-mailer
:message-id:date:subject:from:in-reply-to:to:resent-date:resent-from
:resent-to:resent-subject:resent-message-id:resent-user-agent
:x-scanned-by:x-gm-message-state;
bh=9O67r74ofh9WkEaKTRB/frQ3MKOtQlbCac2mz0/MiyY=;
b=YVAo2/JDMP53RxDmqDEKNcEMtggtfaVyq2DoseZ6vBAfB7G6NtHC9ZEkRs4oGhk6LU
fnyAPe0wnz5d9WINoMAuuTRIhplLxzcqysduSnAJAQ2qqR7mFBnlj9wJeVEKltNwmUME
nPwxsf8go20VBzrZCtECPedcLi60wbl32NCXVn0qwt2LvKiy6ktSS5Xgb4zY8i4dfXAP
6Y5gu32boooWIb9DkH1TJkn3C0RrEugNlw/DUnXrnkFefgxWF3pt/zcoW/wYRyikOdx+
smBClgR9my6QmsS2KsQrMvWJZUva7fddTiZ6FC22e4hW+8Wha0RaZOZu5O7hjg6G4/1g
IEyg==
X-Received: by 10.112.55.9 with SMTP id n9mr5916187lbp.5.1371743600857;
Thu, 20 Jun 2013 08:53:20 -0700 (PDT)
X-Forwarded-To: walter@breakingbad.com
X-Forwarded-For: walter@breakingbad.com
Delivered-To: walter@breakingbad.com
Content-Type: text/html; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
X-Mailer: BlackBerry Email (10.1.0.1720)
Message-ID: <20130619231548.6307981.74194.2379@breakingbad.com>
Date: Wed, 19 Jun 2013 19:15:48 -0400
Subject: Re: [Discourse Meta] [PM] re: Regarding your post in "Site
Customization not working"
From: aaron@breakingbad.com
In-Reply-To: <51c238655a394_5f4e3ce6690667bd@tiefighter2.mail>
To: reply+20c1b0a8bd1a63c0163cc7e7641ca06b@appmail.adventuretime.ooo
ReSent-Date: Thu, 20 Jun 2013 11:53:08 -0400 (EDT)
ReSent-From: Aaron <aaron@breakingbad.com>
ReSent-Subject: Re: [Discourse Meta] [PM] re: Regarding your post in "Site
Customization not working"
X-Gm-Message-State: ALoCoQl1BtN83rAX7At808XAPv1yCqUK3Du2IvK7eCyY3jsI77u4e5cak28307pYYHAo1JlO/Eu9
<html><head></head><body data-blackberry-caret-color=3D"#00a8df" style=3D"b=
ackground-color: rgb(255, 255, 255); line-height: initial;"><div id=3D"BB10=
_response_div" style=3D"width: 100%; font-size: initial; font-family: Calib=
ri, 'Slate Pro', sans-serif; color: rgb(31, 73, 125); text-align: initial; =
background-color: rgb(255, 255, 255);">The EC2 instance - I've seen that th=
ere tends to be odd and unrecommended settings on the Bitnami installs that=
I've checked out.</div> =
=
<div id=3D"response_div_spacer" style=3D"width: 100%; font-size: ini=
tial; font-family: Calibri, 'Slate Pro', sans-serif; color: rgb(31, 73, 125=
); text-align: initial; background-color: rgb(255, 255, 255);"><br style=3D=
"display:initial"></div> =
=
<div id=3D"_signaturePlaceholder" style=3D"font-size: initial; font-=
family: Calibri, 'Slate Pro', sans-serif; color: rgb(31, 73, 125); text-ali=
gn: initial; background-color: rgb(255, 255, 255);"></div> =
=
=
<table width=3D"100%" style=3D"background-color:white;bord=
er-spacing:0px;"> <tbody><tr><td id=3D"_persistentHeaderContainer" colspan=
=3D"2" style=3D"font-size: initial; text-align: initial; background-color: =
rgb(255, 255, 255);"> <div id=
=3D"_persistentHeader" style=3D"border-style: solid none none; border-top-c=
olor: rgb(181, 196, 223); border-top-width: 1pt; padding: 3pt 0in 0in; font=
-family: Tahoma, 'BB Alpha Sans', 'Slate Pro'; font-size: 10pt;"> <div><b>=
From: </b>Grizzly B via Discourse Meta</div><div><b>Sent: </b>Wednesday, J=
une 19, 2013 19:02</div><div><b>To: </b>aaron@breakingbad.com</div><div><b>=
Reply To: </b>Grizzly B via Discourse Meta</div><div><b>Subject: </b>[Disc=
ourse Meta] [PM] re: Regarding your post in "Site Customization<br> not wor=
king"</div></div></td></tr></tbody></table><div id=3D"_persistentHeaderEnd"=
style=3D"border-style: solid none none; border-top-color: rgb(186, 188, 20=
9); border-top-width: 1pt; font-size: initial; text-align: initial; backgro=
und-color: rgb(255, 255, 255);"></div><br><div id=3D"_originalContent" styl=
e=3D""><p>Grizzly B just sent you a private message</p>
<hr><p>Log in to our EC2 instance -or- log into a new DigitalOcean instanc=
e?</p>
<hr><p>Please visit this link to respond: <a href=3D"http://meta.discourse.=
org/t/regarding-your-post-in-site-customization-not-working/7641/5">http://=
meta.discourse.org/t/regarding-your-post-in-site-customization-not-working/=
7641/5</a></p>
<p>To unsubscribe from these emails, visit your <a href=3D"http://meta.disc=
ourse.org/user_preferences">user preferences</a>.</p>
<br><!--end of _originalContent --></div></body></html>

View file

@ -1,205 +0,0 @@
MIME-Version: 1.0
Received: by 10.25.161.144 with HTTP; Tue, 7 Oct 2014 22:17:17 -0700 (PDT)
X-Originating-IP: [117.207.85.84]
In-Reply-To: <5434c8b52bb3a_623ff09fec70f049749@discourse-app.mail>
References: <topic/35@discourse.techapj.com>
<5434c8b52bb3a_623ff09fec70f049749@discourse-app.mail>
Date: Wed, 8 Oct 2014 10:47:17 +0530
Delivered-To: arpit@techapj.com
Message-ID: <CAOJeqne=SJ_LwN4sb-0Y95ejc2OpreVhdmcPn0TnmwSvTCYzzQ@mail.gmail.com>
Subject: Re: [Discourse] [Meta] Welcome to techAPJ's Discourse!
From: Arpit Jalan <arpit@techapj.com>
To: Discourse <mail+e1c7f2a380e33840aeb654f075490bad@arpitjalan.com>
Content-Type: multipart/alternative; boundary=001a114119d8f4e46e0504e26d5b
--001a114119d8f4e46e0504e26d5b
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Awesome!
Pleasure to have you here!
:boom:
On Wed, Oct 8, 2014 at 10:46 AM, ajalan <info@unconfigured.discourse.org>
wrote:
> ajalan
> <http://mandrillapp.com/track/click/30081177/discourse.techapj.com?p=3Dey=
JzIjoiVXgxTTZ3eHpuRWF2QXVoZGRJZVN5MWI0WnhrIiwidiI6MSwicCI6IntcInVcIjozMDA4M=
TE3NyxcInZcIjoxLFwidXJsXCI6XCJodHRwOlxcXC9cXFwvZGlzY291cnNlLnRlY2hhcGouY29t=
XFxcL3VzZXJzXFxcL2FqYWxhblwiLFwiaWRcIjpcIjgyNWI5MDYzZWNmMDRkMjk5OTE4Nzk1MmU=
5YjY2YjE3XCIsXCJ1cmxfaWRzXCI6W1wiNzA3MTNjNTg4MDI3YWQyM2RiM2QwOTVhOGQwYmY4ZT=
YyMzNjYThiMFwiXX0ifQ>
> October 8
>
> Nice to be here! Thanks! [image: smile]
>
> To respond, reply to this email or visit
> http://discourse.techapj.com/t/welcome-to-techapjs-discourse/35/2
> <http://mandrillapp.com/track/click/30081177/discourse.techapj.com?p=3Dey=
JzIjoid1IyWnVqVGRPU2RwLUlFR0Q5QnI1a203eVNjIiwidiI6MSwicCI6IntcInVcIjozMDA4M=
TE3NyxcInZcIjoxLFwidXJsXCI6XCJodHRwOlxcXC9cXFwvZGlzY291cnNlLnRlY2hhcGouY29t=
XFxcL3RcXFwvd2VsY29tZS10by10ZWNoYXBqcy1kaXNjb3Vyc2VcXFwvMzVcXFwvMlwiLFwiaWR=
cIjpcIjgyNWI5MDYzZWNmMDRkMjk5OTE4Nzk1MmU5YjY2YjE3XCIsXCJ1cmxfaWRzXCI6W1wiY2=
RkYzFlZjc5OThhNzE1ODA4Yjg0MGFlNzVlZmNiYmYzYmViODk4Y1wiXX0ifQ>
> in your browser.
> ------------------------------
> Previous Replies techAPJ
> <http://mandrillapp.com/track/click/30081177/discourse.techapj.com?p=3Dey=
JzIjoia2x3LUxac2RSX25uWEFYYWcwVDVha3pIY3RjIiwidiI6MSwicCI6IntcInVcIjozMDA4M=
TE3NyxcInZcIjoxLFwidXJsXCI6XCJodHRwOlxcXC9cXFwvZGlzY291cnNlLnRlY2hhcGouY29t=
XFxcL3VzZXJzXFxcL3RlY2hhcGpcIixcImlkXCI6XCI4MjViOTA2M2VjZjA0ZDI5OTkxODc5NTJ=
lOWI2NmIxN1wiLFwidXJsX2lkc1wiOltcIjk2ZjAyMzVhNmM2NzIyNmU1NjhhMzU1NDE1OTAxNz=
AyYTkxNjM1NzJcIl19In0>
> October 8
>
> Welcome to techAPJ's Discourse!
> ------------------------------
>
> To respond, reply to this email or visit
> http://discourse.techapj.com/t/welcome-to-techapjs-discourse/35/2
> <http://mandrillapp.com/track/click/30081177/discourse.techapj.com?p=3Dey=
JzIjoid1IyWnVqVGRPU2RwLUlFR0Q5QnI1a203eVNjIiwidiI6MSwicCI6IntcInVcIjozMDA4M=
TE3NyxcInZcIjoxLFwidXJsXCI6XCJodHRwOlxcXC9cXFwvZGlzY291cnNlLnRlY2hhcGouY29t=
XFxcL3RcXFwvd2VsY29tZS10by10ZWNoYXBqcy1kaXNjb3Vyc2VcXFwvMzVcXFwvMlwiLFwiaWR=
cIjpcIjgyNWI5MDYzZWNmMDRkMjk5OTE4Nzk1MmU5YjY2YjE3XCIsXCJ1cmxfaWRzXCI6W1wiY2=
RkYzFlZjc5OThhNzE1ODA4Yjg0MGFlNzVlZmNiYmYzYmViODk4Y1wiXX0ifQ>
> in your browser.
>
> To unsubscribe from these emails, visit your user preferences
> <http://mandrillapp.com/track/click/30081177/discourse.techapj.com?p=3Dey=
JzIjoiVTNudkpobl9lUUl0cmdsVVRrcm5iaHpyN0JZIiwidiI6MSwicCI6IntcInVcIjozMDA4M=
TE3NyxcInZcIjoxLFwidXJsXCI6XCJodHRwOlxcXC9cXFwvZGlzY291cnNlLnRlY2hhcGouY29t=
XFxcL215XFxcL3ByZWZlcmVuY2VzXCIsXCJpZFwiOlwiODI1YjkwNjNlY2YwNGQyOTk5MTg3OTU=
yZTliNjZiMTdcIixcInVybF9pZHNcIjpbXCI0OTIyMmMyZDgyNzUwMmQyMGZjYzU4MTZkNjhmYT=
k3NzFkY2YzZDllXCJdfSJ9>
> .
>
--001a114119d8f4e46e0504e26d5b
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Awesome!<div><br></div><div>Pleasure to have you here!</di=
v><div><br></div><div>:boom:</div></div><div class=3D"gmail_extra"><br><div=
class=3D"gmail_quote">On Wed, Oct 8, 2014 at 10:46 AM, ajalan <span dir=3D=
"ltr">&lt;<a href=3D"mailto:info@unconfigured.discourse.org" target=3D"_bla=
nk">info@unconfigured.discourse.org</a>&gt;</span> wrote:<br><blockquote cl=
ass=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;p=
adding-left:1ex"><div>
<table style=3D"margin-bottom:25px;max-width:761px" cellspacing=3D"0" cellp=
adding=3D"0" border=3D"0">
<tbody>
<tr>
<td style=3D"vertical-align:top;width:55px">
<img src=3D"http://discourse.techapj.com/user_avatar/discourse.tech=
apj.com/ajalan/45/35.png" title=3D"ajalan" style=3D"max-width:694px" width=
=3D"45" height=3D"45">
</td>
<td>
<a href=3D"http://mandrillapp.com/track/click/30081177/discourse.te=
chapj.com?p=3DeyJzIjoiVXgxTTZ3eHpuRWF2QXVoZGRJZVN5MWI0WnhrIiwidiI6MSwicCI6I=
ntcInVcIjozMDA4MTE3NyxcInZcIjoxLFwidXJsXCI6XCJodHRwOlxcXC9cXFwvZGlzY291cnNl=
LnRlY2hhcGouY29tXFxcL3VzZXJzXFxcL2FqYWxhblwiLFwiaWRcIjpcIjgyNWI5MDYzZWNmMDR=
kMjk5OTE4Nzk1MmU5YjY2YjE3XCIsXCJ1cmxfaWRzXCI6W1wiNzA3MTNjNTg4MDI3YWQyM2RiM2=
QwOTVhOGQwYmY4ZTYyMzNjYThiMFwiXX0ifQ" style=3D"font-size:13px;font-family:&=
#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;color:#3b5998;text-d=
ecoration:none;font-weight:bold;text-decoration:none;font-weight:bold;color=
:#006699" target=3D"_blank">ajalan</a><br>
<span style=3D"text-align:right;color:#999999;padding-right:5px;fon=
t-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;font-size:=
11px">October 8</span>
</td>
</tr>
<tr>
<td style=3D"padding-top:5px" colspan=3D"2"><p style=3D"margin-top:0;=
border:0">Nice to be here! Thanks! <img src=3D"http://discourse.techapj.com=
/plugins/emoji/images/smile.png" title=3D":smile:" alt=3D"smile" width=3D"2=
0" height=3D"20"></p></td>
</tr>
</tbody>
</table>
<div style=3D"color:#666">
<p>To respond, reply to this email or visit <a href=3D"http://mandrilla=
pp.com/track/click/30081177/discourse.techapj.com?p=3DeyJzIjoid1IyWnVqVGRPU=
2RwLUlFR0Q5QnI1a203eVNjIiwidiI6MSwicCI6IntcInVcIjozMDA4MTE3NyxcInZcIjoxLFwi=
dXJsXCI6XCJodHRwOlxcXC9cXFwvZGlzY291cnNlLnRlY2hhcGouY29tXFxcL3RcXFwvd2VsY29=
tZS10by10ZWNoYXBqcy1kaXNjb3Vyc2VcXFwvMzVcXFwvMlwiLFwiaWRcIjpcIjgyNWI5MDYzZW=
NmMDRkMjk5OTE4Nzk1MmU5YjY2YjE3XCIsXCJ1cmxfaWRzXCI6W1wiY2RkYzFlZjc5OThhNzE1O=
DA4Yjg0MGFlNzVlZmNiYmYzYmViODk4Y1wiXX0ifQ" style=3D"color:#666;text-decorat=
ion:none;font-weight:bold;color:#006699" target=3D"_blank">http://discourse=
.techapj.com/t/welcome-to-techapjs-discourse/35/2</a> in your browser.</p>
</div>
<hr style=3D"background-color:#ddd;min-height:1px;border:1px;background-c=
olor:#ddd;min-height:1px;border:1px">
<h4>Previous Replies</h4>
<table style=3D"margin-bottom:25px;max-width:761px" cellspacing=3D"0" cel=
lpadding=3D"0" border=3D"0">
<tbody>
<tr>
<td style=3D"vertical-align:top;width:55px">
<img src=3D"http://discourse.techapj.com/user_avatar/discourse.tech=
apj.com/techapj/45/34.png" title=3D"techAPJ" style=3D"max-width:694px" widt=
h=3D"45" height=3D"45">
</td>
<td>
<a href=3D"http://mandrillapp.com/track/click/30081177/discourse.te=
chapj.com?p=3DeyJzIjoia2x3LUxac2RSX25uWEFYYWcwVDVha3pIY3RjIiwidiI6MSwicCI6I=
ntcInVcIjozMDA4MTE3NyxcInZcIjoxLFwidXJsXCI6XCJodHRwOlxcXC9cXFwvZGlzY291cnNl=
LnRlY2hhcGouY29tXFxcL3VzZXJzXFxcL3RlY2hhcGpcIixcImlkXCI6XCI4MjViOTA2M2VjZjA=
0ZDI5OTkxODc5NTJlOWI2NmIxN1wiLFwidXJsX2lkc1wiOltcIjk2ZjAyMzVhNmM2NzIyNmU1Nj=
hhMzU1NDE1OTAxNzAyYTkxNjM1NzJcIl19In0" style=3D"font-size:13px;font-family:=
&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;color:#3b5998;text-=
decoration:none;font-weight:bold;text-decoration:none;font-weight:bold;colo=
r:#006699" target=3D"_blank">techAPJ</a><br>
<span style=3D"text-align:right;color:#999999;padding-right:5px;fon=
t-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;font-size:=
11px">October 8</span>
</td>
</tr>
<tr>
<td style=3D"padding-top:5px" colspan=3D"2"><p style=3D"margin-top:0;=
border:0">Welcome to techAPJ&#39;s Discourse!</p></td>
</tr>
</tbody>
</table>
<hr style=3D"background-color:#ddd;min-height:1px;border:1px;background-col=
or:#ddd;min-height:1px;border:1px">
<div style=3D"color:#666">
<p>To respond, reply to this email or visit <a href=3D"http://mandrillapp.c=
om/track/click/30081177/discourse.techapj.com?p=3DeyJzIjoid1IyWnVqVGRPU2RwL=
UlFR0Q5QnI1a203eVNjIiwidiI6MSwicCI6IntcInVcIjozMDA4MTE3NyxcInZcIjoxLFwidXJs=
XCI6XCJodHRwOlxcXC9cXFwvZGlzY291cnNlLnRlY2hhcGouY29tXFxcL3RcXFwvd2VsY29tZS1=
0by10ZWNoYXBqcy1kaXNjb3Vyc2VcXFwvMzVcXFwvMlwiLFwiaWRcIjpcIjgyNWI5MDYzZWNmMD=
RkMjk5OTE4Nzk1MmU5YjY2YjE3XCIsXCJ1cmxfaWRzXCI6W1wiY2RkYzFlZjc5OThhNzE1ODA4Y=
jg0MGFlNzVlZmNiYmYzYmViODk4Y1wiXX0ifQ" style=3D"color:#666;text-decoration:=
none;font-weight:bold;color:#006699" target=3D"_blank">http://discourse.tec=
hapj.com/t/welcome-to-techapjs-discourse/35/2</a> in your browser.</p>
</div><span class=3D"">
<div style=3D"color:#666">
<p>To unsubscribe from these emails, visit your <a href=3D"http://mandrilla=
pp.com/track/click/30081177/discourse.techapj.com?p=3DeyJzIjoiVTNudkpobl9lU=
Ul0cmdsVVRrcm5iaHpyN0JZIiwidiI6MSwicCI6IntcInVcIjozMDA4MTE3NyxcInZcIjoxLFwi=
dXJsXCI6XCJodHRwOlxcXC9cXFwvZGlzY291cnNlLnRlY2hhcGouY29tXFxcL215XFxcL3ByZWZ=
lcmVuY2VzXCIsXCJpZFwiOlwiODI1YjkwNjNlY2YwNGQyOTk5MTg3OTUyZTliNjZiMTdcIixcIn=
VybF9pZHNcIjpbXCI0OTIyMmMyZDgyNzUwMmQyMGZjYzU4MTZkNjhmYTk3NzFkY2YzZDllXCJdf=
SJ9" style=3D"color:#666;text-decoration:none;font-weight:bold;color:#00669=
9" target=3D"_blank">user preferences</a>.</p>
</div>
</span></div>
<img src=3D"http://mandrillapp.com/track/open.php?u=3D30081177&amp;id=3D825=
b9063ecf04d2999187952e9b66b17" height=3D"1" width=3D"1"></blockquote></div>=
<br></div>
--001a114119d8f4e46e0504e26d5b--

10
spec/fixtures/emails/html_reply.eml vendored Normal file
View file

@ -0,0 +1,10 @@
Return-Path: <discourse@bar.com>
From: Foo Bar <discourse@bar.com>
To: reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <18@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir="ltr">This is a <b>HTML</b> reply ;)</div>

View file

@ -0,0 +1,9 @@
Return-Path: <inactive@bar.com>
From: Foo Bar <inactive@bar.com>
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <8@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
Lorem ipsum dolor sit amet, consectetur adipiscing elit.

View file

@ -0,0 +1,76 @@
Return-Path: <discourse@bar.com>
From: Foo Bar <discourse@bar.com>
To: reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <28@foo.bar.mail>
Mime-Version: 1.0
Content-Type: multipart/related; boundary=001a114b2eccff183a052998ec68
--001a114b2eccff183a052998ec68
Content-Type: multipart/alternative; boundary=001a114b2eccff1836052998ec67
--001a114b2eccff1836052998ec67
Content-Type: text/plain; charset=UTF-8
Before
[image: 内嵌图片 1]
After
--001a114b2eccff1836052998ec67
Content-Type: text/html; charset=UTF-8
<div dir="ltr">Before<div><br></div><div><img src="cid:ii_1525434659ddb4cb" alt="内嵌图片 1" style="margin-right: 0px;"><br>
<div><br></div><div>After</div></div></div>
--001a114b2eccff1836052998ec67--
--001a114b2eccff183a052998ec68
Content-Type: image/png; name="logo.png"
Content-Disposition: inline; filename="logo.png"
Content-Transfer-Encoding: base64
Content-ID: <ii_1525434659ddb4cb>
X-Attachment-Id: ii_1525434659ddb4cb
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
uIDrr6oAAAAASUVORK5CYII=
--001a114b2eccff183a052998ec68--

View file

@ -1,37 +0,0 @@
In-Reply-To: <reply@discourse-app.mail>
References: <topic/36@discourse.techapj.com>
<5434ced4ee0f9_663fb0b5f76070593b@discourse-app.mail>
Date: Mon, 1 Dec 2014 20:48:40 +0530
Delivered-To: someone@googlemail.com
Subject: Re: [Discourse] [Meta] Testing reply via email
From: Walter White <walter.white@googlemail.com>
To: Discourse <reply@mail.com>
Content-Type: multipart/alternative; boundary=20cf30363f8522466905092920a6
--20cf30363f8522466905092920a6
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Wed, Oct 8, 2014 at 11:12 AM, techAPJ <info@unconfigured> wrote:
> techAPJ <https://meta.discourse.org/users/techapj>
> November 28
>
> Test reply.
>
> First paragraph.
>
> Second paragraph.
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over
the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown
fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over
the lazy dog. The quick brown fox jumps over the lazy dog.
> First paragraph.
>
> Second paragraph.
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over
the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown

View file

@ -0,0 +1,19 @@
Return-Path: <discourse@bar.com>
From: Foo Bar <discourse@bar.com>
To: reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <24@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
On Tue, Jan 15, 2016 at 11:12 AM, Bar Foo <info@unconfigured.discourse.org> wrote:
> WAT <https://bar.com/users/wat> November 28
>
> This is the previous post.
And this is *my* reply :+1:
> This is another post.
And this is **another** reply.

View file

@ -1,60 +1,15 @@
MIME-Version: 1.0
In-Reply-To: <reply@discourse-app.mail>
References: <topic/36@discourse.techapj.com>
<5434ced4ee0f9_663fb0b5f76070593b@discourse-app.mail>
Date: Mon, 1 Dec 2014 20:48:40 +0530
Delivered-To: someone@googlemail.com
Subject: Re: [Discourse] [Meta] Testing reply via email
From: Walter White <walter.white@googlemail.com>
To: Discourse <reply@mail.com>
Content-Type: multipart/alternative; boundary=20cf30363f8522466905092920a6
--20cf30363f8522466905092920a6
Return-Path: <discourse@bar.com>
From: Foo Bar <discourse@bar.com>
To: reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <23@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Wed, Oct 8, 2014 at 11:12 AM, techAPJ <info@unconfigured.discourse.org>
wrote:
On Tue, Jan 15, 2016 at 11:12 AM, Bar Foo <info@unconfigured.discourse.org> wrote:
> techAPJ <https://meta.discourse.org/users/techapj>
> November 28
>
> Test reply.
>
> First paragraph.
>
> Second paragraph.
>
> To respond, reply to this email or visit
> https://meta.discourse.org/t/testing-default-email-replies/22638/3 in
> your browser.
> ------------------------------
> Previous Replies codinghorror
> <https://meta.discourse.org/users/codinghorror>
> November 28
>
> We're testing the latest GitHub email processing library which we are
> integrating now.
>
> https://github.com/github/email_reply_parser
>
> Go ahead and reply to this topic and I'll reply from various email clients
> for testing.
> ------------------------------
>
> To respond, reply to this email or visit
> https://meta.discourse.org/t/testing-default-email-replies/22638/3 in
> your browser.
>
> To unsubscribe from these emails, visit your user preferences
> <https://meta.discourse.org/my/preferences>.
> WAT <https://bar.com/users/wat> November 28
>
> This is the previous post.
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over
the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown
fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over
the lazy dog. The quick brown fox jumps over the lazy dog.
--20cf30363f8522466905092920a6--
And this is *my* reply :+1:

View file

@ -0,0 +1,11 @@
Return-Path: <insufficient@bar.com>
From: Foo Bar <insufficient@bar.com>
To: category@bar.com
Subject: This is a topic from a complete stranger
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <32@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Hey, this is a topic from a complete stranger ;)

View file

@ -1,136 +0,0 @@
Delivered-To: reply@discourse.org
Return-Path: <walter.white@googlemail.com>
From: Walter White <walter.white@googlemail.com>
Content-Type: multipart/alternative;
boundary=Apple-Mail-B41C7F8E-3639-49B0-A5D5-440E125A7105
Content-Transfer-Encoding: 7bit
Mime-Version: 1.0 (1.0)
Subject: Re: [Discourse Meta] [Lounge] Testing default email replies
Date: Fri, 28 Nov 2014 12:41:41 -0800
References: <topic/22638@meta.discourse.org> <topic/22638/86406@meta.discourse.org>
In-Reply-To: <topic/22638/86406@meta.discourse.org>
To: Discourse Meta <reply@discourse.org>
X-Mailer: iPhone Mail (12B436)
--Apple-Mail-B41C7F8E-3639-49B0-A5D5-440E125A7105
Content-Type: text/plain;
charset=us-ascii
Content-Transfer-Encoding: quoted-printable
### this is a reply from iOS default mail
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over t=
he lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fo=
x jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The q=
uick brown fox jumps over the lazy dog. The quick brown fox jumps over the l=
azy dog.=20
Here's some **bold** markdown text.
Here's a link http://example.com
> On Nov 28, 2014, at 12:35 PM, Arpit Jalan <info@discourse.org> wrote:
>=20
>=20
> techAPJ
> November 28
> Test reply.
>=20
> First paragraph.
>=20
> Second paragraph.
>=20
> To respond, reply to this email or visit https://meta.discourse.org/t/test=
ing-default-email-replies/22638/3 in your browser.
>=20
> Previous Replies
>=20
> codinghorror
> November 28
> We're testing the latest GitHub email processing library which we are inte=
grating now.
>=20
> https://github.com/github/email_reply_parser
>=20
> Go ahead and reply to this topic and I'll reply from various email clients=
for testing.
>=20
> To respond, reply to this email or visit https://meta.discourse.org/t/test=
ing-default-email-replies/22638/3 in your browser.
>=20
> To unsubscribe from these emails, visit your user preferences.
--Apple-Mail-B41C7F8E-3639-49B0-A5D5-440E125A7105
Content-Type: text/html;
charset=utf-8
Content-Transfer-Encoding: 7bit
<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div>### this is a reply from iOS default mail</div><div><br></div><div>The quick brown fox jumps over the lazy dog.&nbsp;<span style="background-color: rgba(255, 255, 255, 0);">The quick brown fox jumps over the lazy dog.&nbsp;The quick brown fox jumps over the lazy dog.&nbsp;The quick brown fox jumps over the lazy dog.&nbsp;The quick brown fox jumps over the lazy dog.&nbsp;The quick brown fox jumps over the lazy dog.&nbsp;The quick brown fox jumps over the lazy dog.&nbsp;</span></div><div><br></div><div>Here's some **bold** markdown text.</div><div><br></div><div>Here's a link <a href="http://example.com">http://example.com</a><br><br></div><div><br>On Nov 28, 2014, at 12:35 PM, Arpit Jalan &lt;<a href="mailto:info@discourse.org">info@discourse.org</a>&gt; wrote:<br><br></div><blockquote type="cite"><div><div>
<table style="margin-bottom:25px;" cellspacing="0" cellpadding="0" border="0">
<tbody>
<tr>
<td style="vertical-align:top;width:55px;">
<img src="https://meta-discourse.global.ssl.fastly.net/user_avatar/meta.discourse.org/techapj/45/3281.png" title="techAPJ" style="max-width:100%;" width="45" height="45">
</td>
<td>
<a href="https://meta.discourse.org/users/techapj" target="_blank" style="text-decoration: none; font-weight: bold; color: #006699;; font-size:13px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;color:#3b5998;text-decoration:none;font-weight:bold">techAPJ</a><br>
<span style="text-align:right;color:#999999;padding-right:5px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;font-size:11px">November 28</span>
</td>
</tr>
<tr>
<td style="padding-top:5px;" colspan="2">
<p style="margin-top:0; border: 0;">Test reply.</p>
<p style="margin-top:0; border: 0;">First paragraph.</p>
<p style="margin-top:0; border: 0;">Second paragraph.</p>
</td>
</tr>
</tbody>
</table>
<div style="color:#666;">
<p>To respond, reply to this email or visit <a href="https://meta.discourse.org/t/testing-default-email-replies/22638/3" style="text-decoration: none; font-weight: bold; color: #006699;; color:#666;">https://meta.discourse.org/t/testing-default-email-replies/22638/3</a> in your browser.</p>
</div>
<hr style="background-color: #ddd; height: 1px; border: 1px;; background-color: #ddd; height: 1px; border: 1px;">
<h4>Previous Replies</h4>
<table style="margin-bottom:25px;" cellspacing="0" cellpadding="0" border="0">
<tbody>
<tr>
<td style="vertical-align:top;width:55px;">
<img src="https://meta-discourse.global.ssl.fastly.net/user_avatar/meta.discourse.org/codinghorror/45/5297.png" title="codinghorror" style="max-width:100%;" width="45" height="45">
</td>
<td>
<a href="https://meta.discourse.org/users/codinghorror" target="_blank" style="text-decoration: none; font-weight: bold; color: #006699;; font-size:13px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;color:#3b5998;text-decoration:none;font-weight:bold">codinghorror</a><br>
<span style="text-align:right;color:#999999;padding-right:5px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;font-size:11px">November 28</span>
</td>
</tr>
<tr>
<td style="padding-top:5px;" colspan="2">
<p style="margin-top:0; border: 0;">We're testing the latest GitHub email processing library which we are integrating now.</p>
<p style="margin-top:0; border: 0;"><a href="https://github.com/github/email_reply_parser" target="_blank" style="text-decoration: none; font-weight: bold; color: #006699;">https://github.com/github/email_reply_parser</a></p>
<p style="margin-top:0; border: 0;">Go ahead and reply to this topic and I'll reply from various email clients for testing.</p>
</td>
</tr>
</tbody>
</table>
<hr style="background-color: #ddd; height: 1px; border: 1px;; background-color: #ddd; height: 1px; border: 1px;">
<div style="color:#666;">
<p>To respond, reply to this email or visit <a href="https://meta.discourse.org/t/testing-default-email-replies/22638/3" style="text-decoration: none; font-weight: bold; color: #006699;; color:#666;">https://meta.discourse.org/t/testing-default-email-replies/22638/3</a> in your browser.</p>
</div>
<div style="color:#666;">
<p>To unsubscribe from these emails, visit your <a href="https://meta.discourse.org/my/preferences" style="text-decoration: none; font-weight: bold; color: #006699;; color:#666;">user preferences</a>.</p>
</div>
</div>
</div></blockquote></body></html>
--Apple-Mail-B41C7F8E-3639-49B0-A5D5-440E125A7105--

View file

@ -1,29 +1,11 @@
Delivered-To: test@mail.com
Return-Path: <walter.white@googlemail.com>
From: Walter White <walter.white@googlemail.com>
Content-Type: multipart/alternative;
boundary=Apple-Mail-8E182EEF-9DBC-41DE-A593-DF2E5EBD3975
Content-Transfer-Encoding: 7bit
Mime-Version: 1.0 (1.0)
Subject: Re: Signature in email replies!
Date: Thu, 23 Oct 2014 14:43:49 +0530
References: <1234@mail.gmail.com>
In-Reply-To: <1234@mail.gmail.com>
To: Arpit Jalan <test@mail.com>
X-Mailer: iPhone Mail (12A405)
Return-Path: <discourse@bar.com>
From: Foo Bar <discourse@bar.com>
To: reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <25@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
This is not the signature you're looking for.
--Apple-Mail-8E182EEF-9DBC-41DE-A593-DF2E5EBD3975
Content-Type: text/plain;
charset=us-ascii
Content-Transfer-Encoding: 7bit
This post should not include signature.
Sent from my iPhone
> On 23-Oct-2014, at 9:45 am, Arpit Jalan <test@mail.com> wrote:
>
> Signature in email replies!
--Apple-Mail-8E182EEF-9DBC-41DE-A593-DF2E5EBD3975
Sent from my iMachine

View file

@ -1,37 +1,10 @@
Return-Path: <FROM>
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 <reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo>; Thu, 13 Jun 2013 17:03:50 -0400
Received: by mail-ie0-f180.google.com with SMTP id f4so21977375iea.25 for <reply+59d8df8370b7e95c5a49fbf86aeb2c93@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: FROM
To: TO
Message-ID: <CADkmRc+rNGAGGbV2iE5p918UVy4UyJqVcXRO2=otppgzduJSg@mail.gmail.com>
Subject: re: [Discourse Meta] eviltrout posted in 'Adventure Time Sux'
Return-Path: <discourse@bar.com>
From: Foo Bar <discourse@bar.com>
To: reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <13@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain;
charset=ISO-8859-1
Content-Type: text/plain
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
LIKE
On Sun, Jun 9, 2013 at 1:39 PM, eviltrout via Discourse Meta
<reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo> wrote:
>
>
>
> eviltrout posted in 'Adventure Time Sux' on Discourse Meta:
>
> ---
> hey guys everyone knows adventure time sucks!
>
> ---
> Please visit this link to respond: http://localhost:3000/t/adventure-time-sux/1234/3
>
> To unsubscribe from these emails, visit your [user preferences](http://localhost:3000/user_preferences).
>
+1

View file

@ -0,0 +1,5 @@
From: Foo Bar <foo@bar.com>
Date: Fri, 15 Jan 2016 00:12:43 +0100
Mime-Version: 1.0
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

View file

@ -1,40 +0,0 @@
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 <reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo>; Thu, 13 Jun 2013 17:03:50 -0400
Received: by mail-ie0-f180.google.com with SMTP id f4so21977375iea.25 for <reply+59d8df8370b7e95c5a49fbf86aeb2c93@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: finn@adventuretime.ooo, reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo
Message-ID: <CADkmRc+rNGAGGbV2iE5p918UVy4UyJqVcXRO2=otppgzduJSg@mail.gmail.com>
Subject: re: [Discourse Meta] eviltrout posted in 'Adventure Time Sux'
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
I could not disagree more. I am obviously biased but adventure time is the
greatest show ever created. Everyone should watch it.
- Jake out
On Sun, Jun 9, 2013 at 1:39 PM, eviltrout via Discourse Meta
<reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo> wrote:
>
>
>
> eviltrout posted in 'Adventure Time Sux' on Discourse Meta:
>
> ---
> hey guys everyone knows adventure time sucks!
>
> ---
> Please visit this link to respond: http://localhost:3000/t/adventure-time-sux/1234/3
>
> To unsubscribe from these emails, visit your [user preferences](http://localhost:3000/user_preferences).
>

View file

@ -1,84 +0,0 @@
In-Reply-To: <test@discourse-app.mail>
Date: Wed, 8 Oct 2014 10:36:19 +0530
Delivered-To: walter.white@googlemail.com
Subject: Re: [Discourse] Welcome to Discourse
From: Walter White <walter.white@googlemail.com>
To: Discourse <mail@arpitjalan.com>
Content-Type: multipart/alternative; boundary=bcaec554078cc3d0c10504e24661
--bcaec554078cc3d0c10504e24661
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
This is my reply.
It is my best reply.
It will also be my *only* reply.
On Wed, Oct 8, 2014 at 10:33 AM, ajalan <info@unconfigured.discourse.org>
wrote:
> ajalan
> <http://mandrillapp.com/track/click/30081177/discourse.techapj.com?p=3Dey=
JzIjoiMGM3a1pGT250VG5sb242RVNTdFdjS1FUSHdzIiwidiI6MSwicCI6IntcInVcIjozMDA4M=
TE3NyxcInZcIjoxLFwidXJsXCI6XCJodHRwOlxcXC9cXFwvZGlzY291cnNlLnRlY2hhcGouY29t=
XFxcL3VzZXJzXFxcL2FqYWxhblwiLFwiaWRcIjpcImQxOWYxYjQ5NTdkODRkMGNhZWY1NDEzZGN=
hODA4YTRhXCIsXCJ1cmxfaWRzXCI6W1wiNzA3MTNjNTg4MDI3YWQyM2RiM2QwOTVhOGQwYmY4ZT=
YyMzNjYThiMFwiXX0ifQ>
> October 8
>
> Awesome! Thank You! [image: +1]
>
> To respond, reply to this email or visit
> http://discourse.techapj.com/t/welcome-to-discourse/8/2
> <http://mandrillapp.com/track/click/30081177/discourse.techapj.com?p=3Dey=
JzIjoibzNWaXFDRDdxSFNCbVRkUmdONlRJVW1ENU8wIiwidiI6MSwicCI6IntcInVcIjozMDA4M=
TE3NyxcInZcIjoxLFwidXJsXCI6XCJodHRwOlxcXC9cXFwvZGlzY291cnNlLnRlY2hhcGouY29t=
XFxcL3RcXFwvd2VsY29tZS10by1kaXNjb3Vyc2VcXFwvOFxcXC8yXCIsXCJpZFwiOlwiZDE5ZjF=
iNDk1N2Q4NGQwY2FlZjU0MTNkY2E4MDhhNGFcIixcInVybF9pZHNcIjpbXCIwYmFkNjE2NDJkNm=
M2NzJhNGU0ZjYzMGU2ZDA5M2I3MzU3NzQ4MzYxXCJdfSJ9>
> in your browser.
> ------------------------------
> Previous Replies system
> <http://mandrillapp.com/track/click/30081177/discourse.techapj.com?p=3Dey=
JzIjoicjFZQm8ySTJjUEtNclpvekZ5ZmFqYmdpTVFNIiwidiI6MSwicCI6IntcInVcIjozMDA4M=
TE3NyxcInZcIjoxLFwidXJsXCI6XCJodHRwOlxcXC9cXFwvZGlzY291cnNlLnRlY2hhcGouY29t=
XFxcL3VzZXJzXFxcL3N5c3RlbVwiLFwiaWRcIjpcImQxOWYxYjQ5NTdkODRkMGNhZWY1NDEzZGN=
hODA4YTRhXCIsXCJ1cmxfaWRzXCI6W1wiMTcxNWU2OTE1M2UzMjk4YmM2Y2NhMWEyM2E5N2ViMW=
U5N2IwMWYyNFwiXX0ifQ>
> October 8
>
> The first paragraph of this pinned topic will be visible as a welcome
> message to all new visitors on your homepage. It's important!
>
> *Edit this* into a brief description of your community:
>
> - Who is it for?
> - What can they find here?
> - Why should they come here?
> - Where can they read more (links, resources, etc)?
>
> You may want to close this topic via the wrench icon at the upper right,
> so that replies don't pile up on an announcement.
> ------------------------------
>
> To respond, reply to this email or visit
> http://discourse.techapj.com/t/welcome-to-discourse/8/2
> <http://mandrillapp.com/track/click/30081177/discourse.techapj.com?p=3Dey=
JzIjoibzNWaXFDRDdxSFNCbVRkUmdONlRJVW1ENU8wIiwidiI6MSwicCI6IntcInVcIjozMDA4M=
TE3NyxcInZcIjoxLFwidXJsXCI6XCJodHRwOlxcXC9cXFwvZGlzY291cnNlLnRlY2hhcGouY29t=
XFxcL3RcXFwvd2VsY29tZS10by1kaXNjb3Vyc2VcXFwvOFxcXC8yXCIsXCJpZFwiOlwiZDE5ZjF=
iNDk1N2Q4NGQwY2FlZjU0MTNkY2E4MDhhNGFcIixcInVybF9pZHNcIjpbXCIwYmFkNjE2NDJkNm=
M2NzJhNGU0ZjYzMGU2ZDA5M2I3MzU3NzQ4MzYxXCJdfSJ9>
> in your browser.
>
> To unsubscribe from these emails, visit your user preferences
> <http://mandrillapp.com/track/click/30081177/discourse.techapj.com?p=3Dey=
JzIjoiaFdWSWtiRGIybjJOeWc0VHRrenAzbnhraU93IiwidiI6MSwicCI6IntcInVcIjozMDA4M=
TE3NyxcInZcIjoxLFwidXJsXCI6XCJodHRwOlxcXC9cXFwvZGlzY291cnNlLnRlY2hhcGouY29t=
XFxcL215XFxcL3ByZWZlcmVuY2VzXCIsXCJpZFwiOlwiZDE5ZjFiNDk1N2Q4NGQwY2FlZjU0MTN=
kY2E4MDhhNGFcIixcInVybF9pZHNcIjpbXCI0OTIyMmMyZDgyNzUwMmQyMGZjYzU4MTZkNjhmYT=
k3NzFkY2YzZDllXCJdfSJ9>
> .
>
--bcaec554078cc3d0c10504e24661

7
spec/fixtures/emails/no_body.eml vendored Normal file
View file

@ -0,0 +1,7 @@
Return-Path: <foo@bar.com>
From: Foo Bar <foo@bar.com>
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <5@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

View file

@ -0,0 +1,75 @@
Return-Path: <discourse@bar.com>
From: Foo Bar <discourse@bar.com>
To: reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <6@foo.bar.mail>
Mime-Version: 1.0
Content-Type: multipart/mixed;
boundary="--==_mimepart_56990c8d3f66c_7cb53ffbb98602004746e";
charset=UTF-8
Content-Transfer-Encoding: 7bit
----==_mimepart_56990c8d3f66c_7cb53ffbb98602004746e
Content-Type: image/png;
charset=UTF-8;
filename=logo.png
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename=logo.png
Content-ID: <56990c92d6c64_7cb53ffbb986020047616@foo.bar.mail>
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
YII=
----==_mimepart_56990c8d3f66c_7cb53ffbb98602004746e--

View file

@ -1,34 +0,0 @@
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 <reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo>; Thu, 13 Jun 2013 17:03:50 -0400
Received: by mail-ie0-f180.google.com with SMTP id f4so21977375iea.25 for <reply+59d8df8370b7e95c5a49fbf86aeb2c93@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: reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo
Message-ID: <CADkmRc+rNGAGGbV2iE5p918UVy4UyJqVcXRO2=otppgzduJSg@mail.gmail.com>
Subject: re: [Discourse Meta] eviltrout posted in 'Adventure Time Sux'
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
On Sun, Jun 9, 2013 at 1:39 PM, eviltrout via Discourse Meta
<reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo> wrote:
>
>
>
> eviltrout posted in 'Adventure Time Sux' on Discourse Meta:
>
> ---
> hey guys everyone knows adventure time sucks!
>
> ---
> Please visit this link to respond: http://localhost:3000/t/adventure-time-sux/1234/3
>
> To unsubscribe from these emails, visit your [user preferences](http://localhost:3000/user_preferences).
>

View file

@ -0,0 +1,7 @@
From: Foo Bar <foo@bar.com>
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <1@foo.bar.mail>
Precedence: list
Mime-Version: 1.0
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

View file

@ -0,0 +1,19 @@
Return-Path: <discourse@bar.com>
From: Foo Bar <discourse@bar.com>
To: reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <20@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
This is the actual reply.
On Tue, Jan 14, 2016 at 0:42 AM, Bar Foo <wat@discourse.org> wrote:
> This is the previous email.
> And it had
>
> a lot
>
>
> of lines ;)

View file

@ -1,277 +0,0 @@
MIME-Version: 1.0
Received: by 10.107.9.17 with HTTP; Tue, 9 Sep 2014 16:18:19 -0700 (PDT)
In-Reply-To: <540f16d4c08d9_4a3f9ff6d61890391c@tiefighter4-meta.mail>
References: <topic/18058@meta.discourse.org>
<540f16d4c08d9_4a3f9ff6d61890391c@tiefighter4-meta.mail>
Date: Tue, 9 Sep 2014 16:18:19 -0700
Delivered-To: kanepyork@gmail.com
Message-ID: <CABeNrKXxfb8YJUWxO5L_oPTGrFsiZfQOpWudk+44Mh=yuUEHNQ@mail.gmail.com>
Subject: Re: [Discourse Meta] Badge icons - where to find them?
From: Kane York <jake@adventuretime.ooo>
To: Discourse Meta <reply+8305e3604ae4d1485dc12b6af6a8446c@appmail.adventuretime.ooo>
Content-Type: multipart/alternative; boundary=001a11c34c389e728f0502aa26a0
--001a11c34c389e728f0502aa26a0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Sure, all you need to do is frobnicate the foobar and you'll be all set!
On Tue, Sep 9, 2014 at 8:03 AM, gordon_ryan <info@discourse.org> wrote:
> gordon_ryan <https://meta.discourse.org/users/gordon_ryan>
> September 9
>
> @riking <https://meta.discourse.org/users/riking>- willing to step by
> step of the custom icon method for an admittedly ignorant admin? Seriousl=
y
> confused.
>
> Or anyone else who knows how to do this [image: smiley]
>
> To respond, reply to this email or visit
> https://meta.discourse.org/t/badge-icons-where-to-find-them/18058/9 in
> your browser.
> ------------------------------
> Previous Replies riking <https://meta.discourse.org/users/riking>
> July 25
>
> Check out the "HTML Head" section in the "Content" tab of the admin panel=
.
> meglio <https://meta.discourse.org/users/meglio>
> July 25
>
> How will it load the related custom font?
> riking <https://meta.discourse.org/users/riking>
> July 25
>
> Here's an example of the styles that FA applies. I'll use <i class=3D"fa
> fa-heart"></i> as the example.
>
> .fa {
> display: inline-block;
> font-family: FontAwesome;
> font-style: normal;
> font-weight: normal;
> line-height: 1;
> -webkit-font-smoothing: antialiased;
> -moz-osx-font-smoothing: grayscale;
> }
> .fa-heart:before {
> content: "\f004";
> }
>
> So you could do this in your site stylesheet:
>
> .fa-custom-burger:before {
> content: "\01f354";
> font-family: inherit;
> }
>
> And get =F0=9F=8D=94 as your badge icon when you enter custom-burger.
> ------------------------------
>
> To respond, reply to this email or visit
> https://meta.discourse.org/t/badge-icons-where-to-find-them/18058/9 in
> your browser.
>
> To unsubscribe from these emails, visit your user preferences
> <https://meta.discourse.org/my/preferences>.
>
--001a11c34c389e728f0502aa26a0
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><span style=3D"font-family:arial,sans-serif;font-size:13px=
">Sure, all you need to do is frobnicate the foobar and you&#39;ll be all s=
et!</span><br><div class=3D"gmail_extra"><br clear=3D"all"><div><br>=
<br><div class=3D"gmail_quote">On Tue, Sep 9, 2014 at 8:03 AM, gordon_ryan =
<span dir=3D"ltr">&lt;<a href=3D"mailto:info@discourse.org" target=3D"_blan=
k">info@discourse.org</a>&gt;</span> wrote:<br><blockquote class=3D"gmail_q=
uote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1e=
x"><div>
<table style=3D"margin-bottom:25px;max-width:761px" cellspacing=3D"0" cellp=
adding=3D"0" border=3D"0">
<tbody>
<tr>
<td style=3D"vertical-align:top;width:55px">
<img src=3D"https://meta-discourse.global.ssl.fastly.net/user_avata=
r/meta.discourse.org/gordon_ryan/45/34017.png" title=3D"gordon_ryan" style=
=3D"max-width:694px" width=3D"45" height=3D"45">
</td>
<td>
<a href=3D"https://meta.discourse.org/users/gordon_ryan" style=3D"f=
ont-size:13px;font-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans=
-serif;color:#3b5998;text-decoration:none;font-weight:bold;text-decoration:=
none;font-weight:bold;color:#006699" target=3D"_blank">gordon_ryan</a><br>
<span style=3D"text-align:right;color:#999999;padding-right:5px;fon=
t-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;font-size:=
11px">September 9</span>
</td>
</tr>
<tr>
<td style=3D"padding-top:5px" colspan=3D"2">
<p style=3D"margin-top:0;border:0"><a href=3D"https://meta.discourse.org/us=
ers/riking" style=3D"text-decoration:none;font-weight:bold;color:#006699" t=
arget=3D"_blank">@riking</a>- willing to step by step of the custom icon me=
thod for an admittedly ignorant admin? Seriously confused.</p>
<p style=3D"margin-top:0;border:0">Or anyone else who knows how to do this =
<img src=3D"https://meta-discourse.global.ssl.fastly.net/plugins/emoji/imag=
es/smiley.png" title=3D":smiley:" alt=3D"smiley" width=3D"20" height=3D"20"=
></p>
</td>
</tr>
</tbody>
</table>
<div style=3D"color:#666">
<p>To respond, reply to this email or visit <a href=3D"https://meta.dis=
course.org/t/badge-icons-where-to-find-them/18058/9" style=3D"color:#666;te=
xt-decoration:none;font-weight:bold;color:#006699" target=3D"_blank">https:=
//meta.discourse.org/t/badge-icons-where-to-find-them/18058/9</a> in your b=
rowser.</p>
</div>
<hr style=3D"background-color:#ddd;min-height:1px;border:1px;background-c=
olor:#ddd;min-height:1px;border:1px">
<h4>Previous Replies</h4>
<table style=3D"margin-bottom:25px;max-width:761px" cellspacing=3D"0" cel=
lpadding=3D"0" border=3D"0">
<tbody>
<tr>
<td style=3D"vertical-align:top;width:55px">
<img src=3D"https://meta-discourse.global.ssl.fastly.net/user_avata=
r/meta.discourse.org/riking/45/9779.png" title=3D"riking" style=3D"max-widt=
h:694px" width=3D"45" height=3D"45">
</td>
<td>
<a href=3D"https://meta.discourse.org/users/riking" style=3D"font-s=
ize:13px;font-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-seri=
f;color:#3b5998;text-decoration:none;font-weight:bold;text-decoration:none;=
font-weight:bold;color:#006699" target=3D"_blank">riking</a><br>
<span style=3D"text-align:right;color:#999999;padding-right:5px;fon=
t-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;font-size:=
11px">July 25</span>
</td>
</tr>
<tr>
<td style=3D"padding-top:5px" colspan=3D"2"><p style=3D"margin-top:0;=
border:0">Check out the &quot;HTML Head&quot; section in the &quot;Content&=
quot; tab of the admin panel.</p></td>
</tr>
</tbody>
</table>
<table style=3D"margin-bottom:25px;max-width:761px" cellspacing=3D"0" cel=
lpadding=3D"0" border=3D"0">
<tbody>
<tr>
<td style=3D"vertical-align:top;width:55px">
<img src=3D"https://meta-discourse.global.ssl.fastly.net/user_avata=
r/meta.discourse.org/meglio/45/33480.png" title=3D"meglio" style=3D"max-wid=
th:694px" width=3D"45" height=3D"45">
</td>
<td>
<a href=3D"https://meta.discourse.org/users/meglio" style=3D"font-s=
ize:13px;font-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-seri=
f;color:#3b5998;text-decoration:none;font-weight:bold;text-decoration:none;=
font-weight:bold;color:#006699" target=3D"_blank">meglio</a><br>
<span style=3D"text-align:right;color:#999999;padding-right:5px;fon=
t-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;font-size:=
11px">July 25</span>
</td>
</tr>
<tr>
<td style=3D"padding-top:5px" colspan=3D"2"><p style=3D"margin-top:0;=
border:0">How will it load the related custom font?</p></td>
</tr>
</tbody>
</table>
<table style=3D"margin-bottom:25px;max-width:761px" cellspacing=3D"0" cel=
lpadding=3D"0" border=3D"0">
<tbody>
<tr>
<td style=3D"vertical-align:top;width:55px">
<img src=3D"https://meta-discourse.global.ssl.fastly.net/user_avata=
r/meta.discourse.org/riking/45/9779.png" title=3D"riking" style=3D"max-widt=
h:694px" width=3D"45" height=3D"45">
</td>
<td>
<a href=3D"https://meta.discourse.org/users/riking" style=3D"font-s=
ize:13px;font-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-seri=
f;color:#3b5998;text-decoration:none;font-weight:bold;text-decoration:none;=
font-weight:bold;color:#006699" target=3D"_blank">riking</a><br>
<span style=3D"text-align:right;color:#999999;padding-right:5px;fon=
t-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;font-size:=
11px">July 25</span>
</td>
</tr>
<tr>
<td style=3D"padding-top:5px" colspan=3D"2">
<p style=3D"margin-top:0;border:0">Here&#39;s an example of the styles that=
FA applies. I&#39;ll use <code style=3D"background-color:#f1f1ff;padding:2=
px 5px">&lt;i class=3D&quot;fa fa-heart&quot;&gt;&lt;/i&gt;</code> as the e=
xample.</p>
<p style=3D"margin-top:0;border:0"></p>
<pre style=3D"word-wrap:break-word;max-width:694px"><code style=3D"backgrou=
nd-color:#f1f1ff;padding:2px 5px;display:block;background-color:#f1f1ff;pad=
ding:5px">.fa {
display: inline-block;
font-family: FontAwesome;
font-style: normal;
font-weight: normal;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.fa-heart:before {
content: &quot;\f004&quot;;
}</code></pre>
<p style=3D"margin-top:0;border:0">So you could do this in your site styles=
heet:</p>
<p style=3D"margin-top:0;border:0"></p>
<pre style=3D"word-wrap:break-word;max-width:694px"><code style=3D"backgrou=
nd-color:#f1f1ff;padding:2px 5px;display:block;background-color:#f1f1ff;pad=
ding:5px">.fa-custom-burger:before {
content: &quot;\01f354&quot;;
font-family: inherit;
}</code></pre>
<p style=3D"margin-top:0;border:0">And get =F0=9F=8D=94 as your badge icon =
when you enter <code style=3D"background-color:#f1f1ff;padding:2px 5px">cus=
tom-burger</code>.</p>
</td>
</tr>
</tbody>
</table>
<hr style=3D"background-color:#ddd;min-height:1px;border:1px;background-col=
or:#ddd;min-height:1px;border:1px">
<div style=3D"color:#666">
<p>To respond, reply to this email or visit <a href=3D"https://meta.discour=
se.org/t/badge-icons-where-to-find-them/18058/9" style=3D"color:#666;text-d=
ecoration:none;font-weight:bold;color:#006699" target=3D"_blank">https://me=
ta.discourse.org/t/badge-icons-where-to-find-them/18058/9</a> in your brows=
er.</p>
</div>
<div style=3D"color:#666">
<p>To unsubscribe from these emails, visit your <a href=3D"https://meta.dis=
course.org/my/preferences" style=3D"color:#666;text-decoration:none;font-we=
ight:bold;color:#006699" target=3D"_blank">user preferences</a>.</p>
</div>
</div>
</blockquote></div><br></div></div>
--001a11c34c389e728f0502aa26a0--

View file

@ -0,0 +1,12 @@
Return-Path: <discourse@bar.com>
From: Foo Bar <discourse@bar.com>
To: reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <27@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
This is a reply :)
---Original Message---
This part should not be included

View file

@ -1,30 +0,0 @@
Delivered-To: test@mail.com
Return-Path: <walter.white@googlemail.com>
From: Walter White <walter.white@googlemail.com>
Content-Type: multipart/alternative;
boundary=Apple-Mail-8E182EEF-9DBC-41DE-A593-DF2E5EBD3975
Content-Transfer-Encoding: 7bit
Mime-Version: 1.0 (1.0)
Subject: Re: Signature in email replies!
Date: Thu, 23 Oct 2014 14:43:49 +0530
References: <1234@mail.gmail.com>
In-Reply-To: <1234@mail.gmail.com>
To: Arpit Jalan <test@mail.com>
X-Mailer: iPhone Mail (12A405)
--Apple-Mail-8E182EEF-9DBC-41DE-A593-DF2E5EBD3975
Content-Type: text/plain;
charset=us-ascii
Content-Transfer-Encoding: 7bit
This post should not include signature.
----Original Message----
Context here.
> On 23-Oct-2014, at 9:45 am, Arpit Jalan <test@mail.com> wrote:
>
> Signature in email replies!
--Apple-Mail-8E182EEF-9DBC-41DE-A593-DF2E5EBD3975

View file

@ -1,188 +0,0 @@
MIME-Version: 1.0
Received: by 10.25.161.144 with HTTP; Tue, 7 Oct 2014 22:17:17 -0700 (PDT)
X-Originating-IP: [117.207.85.84]
In-Reply-To: <5434c8b52bb3a_623ff09fec70f049749@discourse-app.mail>
References: <topic/35@discourse.techapj.com>
<5434c8b52bb3a_623ff09fec70f049749@discourse-app.mail>
Date: Wed, 8 Oct 2014 10:47:17 +0530
Delivered-To: arpit@techapj.com
Message-ID: <CAOJeqne=SJ_LwN4sb-0Y95ejc2OpreVhdmcPn0TnmwSvTCYzzQ@mail.gmail.com>
Subject: Re: [Discourse] [Meta] Welcome to techAPJ's Discourse!
From: Arpit Jalan <arpit@techapj.com>
To: Discourse <mail+e1c7f2a380e33840aeb654f075490bad@arpitjalan.com>Accept-Language: en-US
Content-Language: en-US
X-MS-Has-Attach:
X-MS-TNEF-Correlator:
x-originating-ip: [134.68.31.227]
Content-Type: multipart/alternative;
boundary="_000_B0DFE1BEB3739743BC9B639D0E6BC8FF217A6341IUMSSGMBX104ads_"
MIME-Version: 1.0
--_000_B0DFE1BEB3739743BC9B639D0E6BC8FF217A6341IUMSSGMBX104ads_
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64
TWljcm9zb2Z0IE91dGxvb2sgMjAxMA0KDQpGcm9tOiBtaWNoYWVsIFttYWlsdG86dGFsa0BvcGVu
bXJzLm9yZ10NClNlbnQ6IE1vbmRheSwgT2N0b2JlciAxMywgMjAxNCA5OjM4IEFNDQpUbzogUG93
ZXIsIENocmlzDQpTdWJqZWN0OiBbUE1dIFlvdXIgcG9zdCBpbiAiQnVyZ2VyaGF1czogTmV3IHJl
c3RhdXJhbnQgLyBsdW5jaCB2ZW51ZSINCg0KDQptaWNoYWVsPGh0dHA6Ly9jbC5vcGVubXJzLm9y
Zy90cmFjay9jbGljay8zMDAzOTkwNS90YWxrLm9wZW5tcnMub3JnP3A9ZXlKeklqb2liR2xaYTFW
MGVYaENZMDFNUlRGc1VESm1ZelZRTTBabGVqRTRJaXdpZGlJNk1Td2ljQ0k2SW50Y0luVmNJam96
TURBek9Ua3dOU3hjSW5aY0lqb3hMRndpZFhKc1hDSTZYQ0pvZEhSd2N6cGNYRnd2WEZ4Y0wzUmhi
R3N1YjNCbGJtMXljeTV2Y21kY1hGd3ZkWE5sY25OY1hGd3ZiV2xqYUdGbGJGd2lMRndpYVdSY0lq
cGNJbVExWW1Nd04yTmtORFJqWkRRNE1HTTRZVGcyTXpsalpXSTFOemd6WW1ZMlhDSXNYQ0oxY214
ZmFXUnpYQ0k2VzF3aVlqaGtPRGcxTWprNU56ZG1aalkxWldZeU5URTNPV1JpTkdZeU1XSTNOekZq
TnpoalpqaGtPRndpWFgwaWZRPg0KT2N0b2JlciAxMw0KDQpodHRwczovL3RhbGsub3Blbm1ycy5v
cmcvdC9idXJnZXJoYXVzLW5ldy1yZXN0YXVyYW50LWx1bmNoLXZlbnVlLzY3Mi8zPGh0dHA6Ly9j
bC5vcGVubXJzLm9yZy90cmFjay9jbGljay8zMDAzOTkwNS90YWxrLm9wZW5tcnMub3JnP3A9ZXlK
eklqb2lVRVJJU1VOeVIzbFZNRGRCVlZocFduUjNXV3g0TVdOc1RXNVpJaXdpZGlJNk1Td2ljQ0k2
SW50Y0luVmNJam96TURBek9Ua3dOU3hjSW5aY0lqb3hMRndpZFhKc1hDSTZYQ0pvZEhSd2N6cGNY
Rnd2WEZ4Y0wzUmhiR3N1YjNCbGJtMXljeTV2Y21kY1hGd3ZkRnhjWEM5aWRYSm5aWEpvWVhWekxX
NWxkeTF5WlhOMFlYVnlZVzUwTFd4MWJtTm9MWFpsYm5WbFhGeGNMelkzTWx4Y1hDOHpYQ0lzWENK
cFpGd2lPbHdpWkRWaVl6QTNZMlEwTkdOa05EZ3dZemhoT0RZek9XTmxZalUzT0ROaVpqWmNJaXhj
SW5WeWJGOXBaSE5jSWpwYlhDSmlOelppWWprMFpURmlOekk1WlRrMlpUUmxaV000TkdSbU1qUTRN
RE13WWpZeVlXWXlNR00wWENKZGZTSjk+DQoNCkxvb2tzIGxpa2UgeW91ciByZXBseS1ieS1lbWFp
bCB3YXNuJ3QgcHJvY2Vzc2VkIGNvcnJlY3RseSBieSBvdXIgc29mdHdhcmUuIENhbiB5b3UgbGV0
IG1lIGtub3cgd2hhdCB2ZXJzaW9uL09TIG9mIHdoYXQgZW1haWwgcHJvZ3JhbSB5b3UncmUgdXNp
bmc/IFdlIHdpbGwgd2FudCB0byB0cnkgdG8gZml4IHRoZSBidWcuIDpzbWlsZToNCg0KVGhhbmtz
IQ0KDQoNCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQoNClRvIHJlc3BvbmQsIHJl
cGx5IHRvIHRoaXMgZW1haWwgb3IgdmlzaXQgaHR0cHM6Ly90YWxrLm9wZW5tcnMub3JnL3QveW91
ci1wb3N0LWluLWJ1cmdlcmhhdXMtbmV3LXJlc3RhdXJhbnQtbHVuY2gtdmVudWUvNjc0LzE8aHR0
cDovL2NsLm9wZW5tcnMub3JnL3RyYWNrL2NsaWNrLzMwMDM5OTA1L3RhbGsub3Blbm1ycy5vcmc/
cD1leUp6SWpvaWVYaDJWbnBGTUhSMU1uRm5aRWR1TlhFd01GcFFPVlp0VFZvNElpd2lkaUk2TVN3
aWNDSTZJbnRjSW5WY0lqb3pNREF6T1Rrd05TeGNJblpjSWpveExGd2lkWEpzWENJNlhDSm9kSFJ3
Y3pwY1hGd3ZYRnhjTDNSaGJHc3ViM0JsYm0xeWN5NXZjbWRjWEZ3dmRGeGNYQzk1YjNWeUxYQnZj
M1F0YVc0dFluVnlaMlZ5YUdGMWN5MXVaWGN0Y21WemRHRjFjbUZ1ZEMxc2RXNWphQzEyWlc1MVpW
eGNYQzgyTnpSY1hGd3ZNVndpTEZ3aWFXUmNJanBjSW1RMVltTXdOMk5rTkRSalpEUTRNR000WVRn
Mk16bGpaV0kxTnpnelltWTJYQ0lzWENKMWNteGZhV1J6WENJNlcxd2lZamMyWW1JNU5HVXhZamN5
T1dVNU5tVTBaV1ZqT0RSa1pqSTBPREF6TUdJMk1tRm1NakJqTkZ3aVhYMGlmUT4gaW4geW91ciBi
cm93c2VyLg0KDQpUbyB1bnN1YnNjcmliZSBmcm9tIHRoZXNlIGVtYWlscywgdmlzaXQgeW91ciB1
c2VyIHByZWZlcmVuY2VzPGh0dHA6Ly9jbC5vcGVubXJzLm9yZy90cmFjay9jbGljay8zMDAzOTkw
NS90YWxrLm9wZW5tcnMub3JnP3A9ZXlKeklqb2lkVXh1V2xnNVZGYzBPV1pXUzBZNGJGZExkbWx5
V0dzeFRWOXpJaXdpZGlJNk1Td2ljQ0k2SW50Y0luVmNJam96TURBek9Ua3dOU3hjSW5aY0lqb3hM
RndpZFhKc1hDSTZYQ0pvZEhSd2N6cGNYRnd2WEZ4Y0wzUmhiR3N1YjNCbGJtMXljeTV2Y21kY1hG
d3ZiWGxjWEZ3dmNISmxabVZ5Wlc1alpYTmNJaXhjSW1sa1hDSTZYQ0prTldKak1EZGpaRFEwWTJR
ME9EQmpPR0U0TmpNNVkyVmlOVGM0TTJKbU5sd2lMRndpZFhKc1gybGtjMXdpT2x0Y0ltSTRNV1V3
WmpBMU5EWTVORE0wTnpneU0yRm1NakEyTmpGalpqYzNaR05pTjJOaFl6ZG1NakpjSWwxOUluMD4u
DQoNCg==
--_000_B0DFE1BEB3739743BC9B639D0E6BC8FF217A6341IUMSSGMBX104ads_
Content-Type: text/html; charset="utf-8"
Content-Transfer-Encoding: base64
PGh0bWwgeG1sbnM6dj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp2bWwiIHhtbG5zOm89InVy
bjpzY2hlbWFzLW1pY3Jvc29mdC1jb206b2ZmaWNlOm9mZmljZSIgeG1sbnM6dz0idXJuOnNjaGVt
YXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6d29yZCIgeG1sbnM6bT0iaHR0cDovL3NjaGVtYXMubWlj
cm9zb2Z0LmNvbS9vZmZpY2UvMjAwNC8xMi9vbW1sIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv
VFIvUkVDLWh0bWw0MCI+DQo8aGVhZD4NCjxtZXRhIGh0dHAtZXF1aXY9IkNvbnRlbnQtVHlwZSIg
Y29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04Ij4NCjxtZXRhIG5hbWU9IkdlbmVyYXRv
ciIgY29udGVudD0iTWljcm9zb2Z0IFdvcmQgMTQgKGZpbHRlcmVkIG1lZGl1bSkiPg0KPCEtLVtp
ZiAhbXNvXT48c3R5bGU+dlw6KiB7YmVoYXZpb3I6dXJsKCNkZWZhdWx0I1ZNTCk7fQ0Kb1w6KiB7
YmVoYXZpb3I6dXJsKCNkZWZhdWx0I1ZNTCk7fQ0Kd1w6KiB7YmVoYXZpb3I6dXJsKCNkZWZhdWx0
I1ZNTCk7fQ0KLnNoYXBlIHtiZWhhdmlvcjp1cmwoI2RlZmF1bHQjVk1MKTt9DQo8L3N0eWxlPjwh
W2VuZGlmXS0tPjxzdHlsZT48IS0tDQovKiBGb250IERlZmluaXRpb25zICovDQpAZm9udC1mYWNl
DQoJe2ZvbnQtZmFtaWx5OkNhbGlicmk7DQoJcGFub3NlLTE6MiAxNSA1IDIgMiAyIDQgMyAyIDQ7
fQ0KQGZvbnQtZmFjZQ0KCXtmb250LWZhbWlseTpUYWhvbWE7DQoJcGFub3NlLTE6MiAxMSA2IDQg
MyA1IDQgNCAyIDQ7fQ0KLyogU3R5bGUgRGVmaW5pdGlvbnMgKi8NCnAuTXNvTm9ybWFsLCBsaS5N
c29Ob3JtYWwsIGRpdi5Nc29Ob3JtYWwNCgl7bWFyZ2luOjBpbjsNCgltYXJnaW4tYm90dG9tOi4w
MDAxcHQ7DQoJZm9udC1zaXplOjEyLjBwdDsNCglmb250LWZhbWlseToiVGltZXMgTmV3IFJvbWFu
Iiwic2VyaWYiO30NCmE6bGluaywgc3Bhbi5Nc29IeXBlcmxpbmsNCgl7bXNvLXN0eWxlLXByaW9y
aXR5Ojk5Ow0KCWNvbG9yOmJsdWU7DQoJdGV4dC1kZWNvcmF0aW9uOnVuZGVybGluZTt9DQphOnZp
c2l0ZWQsIHNwYW4uTXNvSHlwZXJsaW5rRm9sbG93ZWQNCgl7bXNvLXN0eWxlLXByaW9yaXR5Ojk5
Ow0KCWNvbG9yOnB1cnBsZTsNCgl0ZXh0LWRlY29yYXRpb246dW5kZXJsaW5lO30NCnANCgl7bXNv
LXN0eWxlLXByaW9yaXR5Ojk5Ow0KCW1zby1tYXJnaW4tdG9wLWFsdDphdXRvOw0KCW1hcmdpbi1y
aWdodDowaW47DQoJbXNvLW1hcmdpbi1ib3R0b20tYWx0OmF1dG87DQoJbWFyZ2luLWxlZnQ6MGlu
Ow0KCWZvbnQtc2l6ZToxMi4wcHQ7DQoJZm9udC1mYW1pbHk6IlRpbWVzIE5ldyBSb21hbiIsInNl
cmlmIjt9DQpzcGFuLkVtYWlsU3R5bGUxOA0KCXttc28tc3R5bGUtdHlwZTpwZXJzb25hbC1yZXBs
eTsNCglmb250LWZhbWlseToiQ2FsaWJyaSIsInNhbnMtc2VyaWYiOw0KCWNvbG9yOiMxRjQ5N0Q7
fQ0KLk1zb0NocERlZmF1bHQNCgl7bXNvLXN0eWxlLXR5cGU6ZXhwb3J0LW9ubHk7DQoJZm9udC1m
YW1pbHk6IkNhbGlicmkiLCJzYW5zLXNlcmlmIjt9DQpAcGFnZSBXb3JkU2VjdGlvbjENCgl7c2l6
ZTo4LjVpbiAxMS4waW47DQoJbWFyZ2luOjEuMGluIDEuMGluIDEuMGluIDEuMGluO30NCmRpdi5X
b3JkU2VjdGlvbjENCgl7cGFnZTpXb3JkU2VjdGlvbjE7fQ0KLS0+PC9zdHlsZT48IS0tW2lmIGd0
ZSBtc28gOV0+PHhtbD4NCjxvOnNoYXBlZGVmYXVsdHMgdjpleHQ9ImVkaXQiIHNwaWRtYXg9IjEw
MjYiIC8+DQo8L3htbD48IVtlbmRpZl0tLT48IS0tW2lmIGd0ZSBtc28gOV0+PHhtbD4NCjxvOnNo
YXBlbGF5b3V0IHY6ZXh0PSJlZGl0Ij4NCjxvOmlkbWFwIHY6ZXh0PSJlZGl0IiBkYXRhPSIxIiAv
Pg0KPC9vOnNoYXBlbGF5b3V0PjwveG1sPjwhW2VuZGlmXS0tPg0KPC9oZWFkPg0KPGJvZHkgbGFu
Zz0iRU4tVVMiIGxpbms9ImJsdWUiIHZsaW5rPSJwdXJwbGUiPg0KPGRpdiBjbGFzcz0iV29yZFNl
Y3Rpb24xIj4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEu
MHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90
Oztjb2xvcjojMUY0OTdEIj5NaWNyb3NvZnQgT3V0bG9vayAyMDEwPG86cD48L286cD48L3NwYW4+
PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7
Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2Nv
bG9yOiMxRjQ5N0QiPjxvOnA+Jm5ic3A7PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29O
b3JtYWwiPjxiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTAuMHB0O2ZvbnQtZmFtaWx5OiZxdW90
O1RhaG9tYSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7Ij5Gcm9tOjwvc3Bhbj48L2I+PHNw
YW4gc3R5bGU9ImZvbnQtc2l6ZToxMC4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7VGFob21hJnF1b3Q7
LCZxdW90O3NhbnMtc2VyaWYmcXVvdDsiPiBtaWNoYWVsIFttYWlsdG86dGFsa0BvcGVubXJzLm9y
Z10NCjxicj4NCjxiPlNlbnQ6PC9iPiBNb25kYXksIE9jdG9iZXIgMTMsIDIwMTQgOTozOCBBTTxi
cj4NCjxiPlRvOjwvYj4gUG93ZXIsIENocmlzPGJyPg0KPGI+U3ViamVjdDo8L2I+IFtQTV0gWW91
ciBwb3N0IGluICZxdW90O0J1cmdlcmhhdXM6IE5ldyByZXN0YXVyYW50IC8gbHVuY2ggdmVudWUm
cXVvdDs8bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48bzpwPiZu
YnNwOzwvbzpwPjwvcD4NCjxkaXY+DQo8dGFibGUgY2xhc3M9Ik1zb05vcm1hbFRhYmxlIiBib3Jk
ZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCI+DQo8dGJvZHk+DQo8dHI+DQo8
dGQgdmFsaWduPSJ0b3AiIHN0eWxlPSJwYWRkaW5nOjBpbiAwaW4gMGluIDBpbiI+PC90ZD4NCjx0
ZCBzdHlsZT0icGFkZGluZzowaW4gMGluIDBpbiAwaW4iPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCIg
c3R5bGU9Im1hcmdpbi1ib3R0b206MTguNzVwdCI+PGEgaHJlZj0iaHR0cDovL2NsLm9wZW5tcnMu
b3JnL3RyYWNrL2NsaWNrLzMwMDM5OTA1L3RhbGsub3Blbm1ycy5vcmc/cD1leUp6SWpvaWJHbFph
MVYwZVhoQ1kwMU1SVEZzVURKbVl6VlFNMFpsZWpFNElpd2lkaUk2TVN3aWNDSTZJbnRjSW5WY0lq
b3pNREF6T1Rrd05TeGNJblpjSWpveExGd2lkWEpzWENJNlhDSm9kSFJ3Y3pwY1hGd3ZYRnhjTDNS
aGJHc3ViM0JsYm0xeWN5NXZjbWRjWEZ3dmRYTmxjbk5jWEZ3dmJXbGphR0ZsYkZ3aUxGd2lhV1Jj
SWpwY0ltUTFZbU13TjJOa05EUmpaRFE0TUdNNFlUZzJNemxqWldJMU56Z3pZbVkyWENJc1hDSjFj
bXhmYVdSelhDSTZXMXdpWWpoa09EZzFNams1TnpkbVpqWTFaV1l5TlRFM09XUmlOR1l5TVdJM056
RmpOemhqWmpoa09Gd2lYWDBpZlEiIHRhcmdldD0iX2JsYW5rIj48Yj48c3BhbiBzdHlsZT0iZm9u
dC1zaXplOjEwLjBwdDtmb250LWZhbWlseTomcXVvdDtUYWhvbWEmcXVvdDssJnF1b3Q7c2Fucy1z
ZXJpZiZxdW90Oztjb2xvcjojMDA2Njk5O3RleHQtZGVjb3JhdGlvbjpub25lIj5taWNoYWVsPC9z
cGFuPjwvYj48L2E+PGJyPg0KPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTo4LjVwdDtmb250LWZhbWls
eTomcXVvdDtUYWhvbWEmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojOTk5OTk5
Ij5PY3RvYmVyIDEzPC9zcGFuPg0KPG86cD48L286cD48L3A+DQo8L3RkPg0KPC90cj4NCjx0cj4N
Cjx0ZCBjb2xzcGFuPSIyIiBzdHlsZT0icGFkZGluZzozLjc1cHQgMGluIDBpbiAwaW4iPg0KPHAg
Y2xhc3M9Ik1zb05vcm1hbCIgc3R5bGU9Im1hcmdpbi1ib3R0b206MTguNzVwdCI+PGEgaHJlZj0i
aHR0cDovL2NsLm9wZW5tcnMub3JnL3RyYWNrL2NsaWNrLzMwMDM5OTA1L3RhbGsub3Blbm1ycy5v
cmc/cD1leUp6SWpvaVVFUklTVU55UjNsVk1EZEJWVmhwV25SM1dXeDRNV05zVFc1Wklpd2lkaUk2
TVN3aWNDSTZJbnRjSW5WY0lqb3pNREF6T1Rrd05TeGNJblpjSWpveExGd2lkWEpzWENJNlhDSm9k
SFJ3Y3pwY1hGd3ZYRnhjTDNSaGJHc3ViM0JsYm0xeWN5NXZjbWRjWEZ3dmRGeGNYQzlpZFhKblpY
Sm9ZWFZ6TFc1bGR5MXlaWE4wWVhWeVlXNTBMV3gxYm1Ob0xYWmxiblZsWEZ4Y0x6WTNNbHhjWEM4
elhDSXNYQ0pwWkZ3aU9sd2laRFZpWXpBM1kyUTBOR05rTkRnd1l6aGhPRFl6T1dObFlqVTNPRE5p
WmpaY0lpeGNJblZ5YkY5cFpITmNJanBiWENKaU56WmlZamswWlRGaU56STVaVGsyWlRSbFpXTTRO
R1JtTWpRNE1ETXdZall5WVdZeU1HTTBYQ0pkZlNKOSI+PGI+PHNwYW4gc3R5bGU9ImNvbG9yOiMw
MDY2OTk7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPmh0dHBzOi8vdGFsay5vcGVubXJzLm9yZy90L2J1
cmdlcmhhdXMtbmV3LXJlc3RhdXJhbnQtbHVuY2gtdmVudWUvNjcyLzM8L3NwYW4+PC9iPjwvYT4N
CjxvOnA+PC9vOnA+PC9wPg0KPHAgc3R5bGU9Im1hcmdpbi10b3A6MGluIj5Mb29rcyBsaWtlIHlv
dXIgcmVwbHktYnktZW1haWwgd2Fzbid0IHByb2Nlc3NlZCBjb3JyZWN0bHkgYnkgb3VyIHNvZnR3
YXJlLiBDYW4geW91IGxldCBtZSBrbm93IHdoYXQgdmVyc2lvbi9PUyBvZiB3aGF0IGVtYWlsIHBy
b2dyYW0geW91J3JlIHVzaW5nPyBXZSB3aWxsIHdhbnQgdG8gdHJ5IHRvIGZpeCB0aGUgYnVnLiA6
c21pbGU6PG86cD48L286cD48L3A+DQo8cCBzdHlsZT0ibWFyZ2luLXRvcDowaW4iPlRoYW5rcyE8
bzpwPjwvbzpwPjwvcD4NCjwvdGQ+DQo8L3RyPg0KPC90Ym9keT4NCjwvdGFibGU+DQo8ZGl2IGNs
YXNzPSJNc29Ob3JtYWwiIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJ0ZXh0LWFsaWduOmNlbnRlciI+
DQo8aHIgc2l6ZT0iMSIgd2lkdGg9IjEwMCUiIGFsaWduPSJjZW50ZXIiPg0KPC9kaXY+DQo8ZGl2
Pg0KPHA+PHNwYW4gc3R5bGU9ImNvbG9yOiM2NjY2NjYiPlRvIHJlc3BvbmQsIHJlcGx5IHRvIHRo
aXMgZW1haWwgb3IgdmlzaXQgPGEgaHJlZj0iaHR0cDovL2NsLm9wZW5tcnMub3JnL3RyYWNrL2Ns
aWNrLzMwMDM5OTA1L3RhbGsub3Blbm1ycy5vcmc/cD1leUp6SWpvaWVYaDJWbnBGTUhSMU1uRm5a
RWR1TlhFd01GcFFPVlp0VFZvNElpd2lkaUk2TVN3aWNDSTZJbnRjSW5WY0lqb3pNREF6T1Rrd05T
eGNJblpjSWpveExGd2lkWEpzWENJNlhDSm9kSFJ3Y3pwY1hGd3ZYRnhjTDNSaGJHc3ViM0JsYm0x
eWN5NXZjbWRjWEZ3dmRGeGNYQzk1YjNWeUxYQnZjM1F0YVc0dFluVnlaMlZ5YUdGMWN5MXVaWGN0
Y21WemRHRjFjbUZ1ZEMxc2RXNWphQzEyWlc1MVpWeGNYQzgyTnpSY1hGd3ZNVndpTEZ3aWFXUmNJ
anBjSW1RMVltTXdOMk5rTkRSalpEUTRNR000WVRnMk16bGpaV0kxTnpnelltWTJYQ0lzWENKMWNt
eGZhV1J6WENJNlcxd2lZamMyWW1JNU5HVXhZamN5T1dVNU5tVTBaV1ZqT0RSa1pqSTBPREF6TUdJ
Mk1tRm1NakJqTkZ3aVhYMGlmUSI+DQo8Yj48c3BhbiBzdHlsZT0iY29sb3I6IzAwNjY5OTt0ZXh0
LWRlY29yYXRpb246bm9uZSI+aHR0cHM6Ly90YWxrLm9wZW5tcnMub3JnL3QveW91ci1wb3N0LWlu
LWJ1cmdlcmhhdXMtbmV3LXJlc3RhdXJhbnQtbHVuY2gtdmVudWUvNjc0LzE8L3NwYW4+PC9iPjwv
YT4gaW4geW91ciBicm93c2VyLjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjwvZGl2Pg0KPGRpdj4N
CjxwPjxzcGFuIHN0eWxlPSJjb2xvcjojNjY2NjY2Ij5UbyB1bnN1YnNjcmliZSBmcm9tIHRoZXNl
IGVtYWlscywgdmlzaXQgeW91ciA8YSBocmVmPSJodHRwOi8vY2wub3Blbm1ycy5vcmcvdHJhY2sv
Y2xpY2svMzAwMzk5MDUvdGFsay5vcGVubXJzLm9yZz9wPWV5SnpJam9pZFV4dVdsZzVWRmMwT1da
V1MwWTRiRmRMZG1seVdHc3hUVjl6SWl3aWRpSTZNU3dpY0NJNkludGNJblZjSWpvek1EQXpPVGt3
TlN4Y0luWmNJam94TEZ3aWRYSnNYQ0k2WENKb2RIUndjenBjWEZ3dlhGeGNMM1JoYkdzdWIzQmxi
bTF5Y3k1dmNtZGNYRnd2YlhsY1hGd3ZjSEpsWm1WeVpXNWpaWE5jSWl4Y0ltbGtYQ0k2WENKa05X
SmpNRGRqWkRRMFkyUTBPREJqT0dFNE5qTTVZMlZpTlRjNE0ySm1ObHdpTEZ3aWRYSnNYMmxrYzF3
aU9sdGNJbUk0TVdVd1pqQTFORFk1TkRNME56Z3lNMkZtTWpBMk5qRmpaamMzWkdOaU4yTmhZemRt
TWpKY0lsMTlJbjAiPg0KPGI+PHNwYW4gc3R5bGU9ImNvbG9yOiMwMDY2OTk7dGV4dC1kZWNvcmF0
aW9uOm5vbmUiPnVzZXIgcHJlZmVyZW5jZXM8L3NwYW4+PC9iPjwvYT4uPG86cD48L286cD48L3Nw
YW4+PC9wPg0KPC9kaXY+DQo8L2Rpdj4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxpbWcgYm9yZGVy
PSIwIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBpZD0iX3gwMDAwX2kxMDI2IiBzcmM9Imh0dHA6Ly9j
bC5vcGVubXJzLm9yZy90cmFjay9vcGVuLnBocD91PTMwMDM5OTA1JmFtcDtpZD1kNWJjMDdjZDQ0
Y2Q0ODBjOGE4NjM5Y2ViNTc4M2JmNiI+PG86cD48L286cD48L3A+DQo8L2Rpdj4NCjwvYm9keT4N
CjwvaHRtbD4NCg==
--_000_B0DFE1BEB3739743BC9B639D0E6BC8FF217A6341IUMSSGMBX104ads_--

View file

@ -1,7 +0,0 @@
<p>Is there any reason the <em>old</em> candy can't be be kept in silos while the new candy
is imported into <em>new</em> silos?</p>
<p>The thing about candy is it stays delicious for a long time -- we can just keep
it there without worrying about it too much, imo.</p>
<p>Thanks for listening.</p>

View file

@ -1,42 +1,12 @@
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 <reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo>; Thu, 13 Jun 2013 17:03:50 -0400
Received: by mail-ie0-f180.google.com with SMTP id f4so21977375iea.25 for <reply+59d8df8370b7e95c5a49fbf86aeb2c93@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: reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo
Message-ID: <CADkmRc+rNGAGGbV2iE5p918UVy4UyJqVcXRO2=otppgzduJSg@mail.gmail.com>
Subject: re: [Discourse Meta] eviltrout posted in 'Adventure Time Sux'
Return-Path: <discourse@bar.com>
From: Foo Bar <discourse@bar.com>
To: reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <22@foo.bar.mail>
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
Content-Type: text/plain; charset=UTF-8
Is there any reason the *old* candy can't be be kept in silos while the new candy
is imported into *new* silos?
Do you like liquorice?
The thing about candy is it stays delicious for a long time -- we can just keep
it there without worrying about it too much, imo.
Thanks for listening.
On Sun, Jun 9, 2013 at 1:39 PM, eviltrout via Discourse Meta
<reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo> wrote:
>
>
>
> eviltrout posted in 'Adventure Time Sux' on Discourse Meta:
>
> ---
> hey guys everyone knows adventure time sucks!
>
> ---
> Please visit this link to respond: http://localhost:3000/t/adventure-time-sux/1234/3
>
> To unsubscribe from these emails, visit your [user preferences](http://localhost:3000/user_preferences).
>
I really like them. One could even say that I am *addicted* to liquorice. Anf if
you can mix it up with some anise, then I'm in heaven ;)

View file

@ -1,37 +0,0 @@
Return-Path: <FROM>
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 <reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo>; Thu, 13 Jun 2013 17:03:50 -0400
Received: by mail-ie0-f180.google.com with SMTP id f4so21977375iea.25 for <reply+59d8df8370b7e95c5a49fbf86aeb2c93@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: FROM
To: TO
Message-ID: <CADkmRc+rNGAGGbV2iE5p918UVy4UyJqVcXRO2=otppgzduJSg@mail.gmail.com>
Subject: re: [Discourse Meta] eviltrout posted in 'Adventure Time Sux'
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
+1
On Sun, Jun 9, 2013 at 1:39 PM, eviltrout via Discourse Meta
<reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo> wrote:
>
>
>
> eviltrout posted in 'Adventure Time Sux' on Discourse Meta:
>
> ---
> hey guys everyone knows adventure time sucks!
>
> ---
> Please visit this link to respond: http://localhost:3000/t/adventure-time-sux/1234/3
>
> To unsubscribe from these emails, visit your [user preferences](http://localhost:3000/user_preferences).
>

View file

@ -1,38 +0,0 @@
Delivered-To: discourse-reply+cd480e301683c9902891f15968bf07a5@discourse.org
Received: by 10.194.216.104 with SMTP id op8csp80593wjc;
Wed, 24 Jul 2013 07:59:14 -0700 (PDT)
Return-Path: <walter.white@googlemail.com>
References: <topic/5043@discourse.org> <51efeb9b36c34_66dc2dfce6811866@discourse.mail>
From: Walter White <walter.white@googlemail.com>
In-Reply-To: <51efeb9b36c34_66dc2dfce6811866@discourse.mail>
Mime-Version: 1.0 (1.0)
Date: Wed, 24 Jul 2013 15:59:10 +0100
Message-ID: <4597127794206131679@unknownmsgid>
Subject: Re: [Discourse] new reply to your post in 'Crystal Blue'
To: walter via Discourse <reply+cd480e301683c9902891f15968bf07a5@appmail.adventuretime.ooo>
Content-Type: multipart/alternative; boundary=001a11c20edc15a39304e2432790
This will not include the previous discussion that is present in this email.
------------------------------
Previous discussion
skylerwhite<http://discourse.org/users/skylerwhite> July 24
This is a reply.
fring <http://discourse.org/users/fring> July 24
This is an older reply.
hank_schrader <http://discourse.org/users/hank_schrader> July 24
Of course another reply here.
walterwhite <http://discourse.org/users/walterwhite> July 24
------------------------------
To respond, reply to this email or visit
http://discourse.org/t/crystal-blue/5043/10in
your browser.
To unsubscribe from these emails, visit your user
preferences<http://discourse.org/user_preferences>
.

View file

@ -1,180 +1,23 @@
Delivered-To: reply@discourse.org
MIME-Version: 1.0
In-Reply-To: <topic/22638/86406@meta.discourse.org>
References: <topic/22638@meta.discourse.org>
<topic/22638/86406@meta.discourse.org>
Date: Fri, 28 Nov 2014 12:55:32 -0800
Subject: Re: [Discourse Meta] [Lounge] Testing default email replies
From: Walter White <walter.white@googlemail.com>
To: Discourse Meta <reply@discourse.org>
Content-Type: multipart/alternative; boundary=001a1137c9285318bb0508f17bc5
--001a1137c9285318bb0508f17bc5
Return-Path: <discourse@bar.com>
From: Foo Bar <discourse@bar.com>
To: reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <21@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
### this is a reply from iOS Gmail app
This will not include the previous discussion that is present in this email.
The quick brown fox jumps over the lazy dog. The quick brown fox jumps over
the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown
fox jumps over the lazy dog. The quick brown fox jumps over the lazy
dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps
over the lazy dog.
---
*Previous Replies*
This is **bold** text in Markdown.
This is previous reply #1.
This is a link to http://example.com
Posted by foo bar on 01/15/2016
On Friday, November 28, 2014, Arpit Jalan <info@discourse.org> wrote:
---
[Visit the Topic](https://bar.com/t/wat/1/1) to respond.
> techAPJ <https://meta.discourse.org/users/techapj>
> November 28
>
> Test reply.
>
> First paragraph.
>
> Second paragraph.
>
> To respond, reply to this email or visit
> https://meta.discourse.org/t/testing-default-email-replies/22638/3 in
> your browser.
> ------------------------------
> Previous Replies codinghorror
> <https://meta.discourse.org/users/codinghorror>
> November 28
>
> We're testing the latest GitHub email processing library which we are
> integrating now.
>
> https://github.com/github/email_reply_parser
>
> Go ahead and reply to this topic and I'll reply from various email clients
> for testing.
> ------------------------------
>
> To respond, reply to this email or visit
> https://meta.discourse.org/t/testing-default-email-replies/22638/3 in
> your browser.
>
> To unsubscribe from these emails, visit your user preferences
> <https://meta.discourse.org/my/preferences>.
>
--001a1137c9285318bb0508f17bc5
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
### this is a reply from iOS Gmail app<div><br></div><div>The quick brown f=
ox jumps over the lazy dog.=C2=A0<font><span style=3D"background-color:rgba=
(255,255,255,0)">The quick brown fox jumps over the lazy dog.=C2=A0The quic=
k brown fox jumps over the lazy dog.=C2=A0The quick brown fox jumps over th=
e lazy dog.=C2=A0The quick brown fox jumps over the lazy dog.=C2=A0The quic=
k brown fox jumps over the lazy dog.=C2=A0The quick brown fox jumps over th=
e lazy dog.=C2=A0</span></font></div><div><font><span style><br></span></fo=
nt></div><div><font><span style>This is **bold** text in Markdown.</span></=
font></div><div><font><span style><br></span></font></div><div><font><span =
style>This is a link to <a href=3D"http://example.com">http://example.com</=
a><br></span></font><br>On Friday, November 28, 2014, Arpit Jalan &lt;<a hr=
ef=3D"mailto:info@discourse.org">info@discourse.org</a>&gt; wrote:<br><bloc=
kquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #cc=
c solid;padding-left:1ex"><div>
<table style=3D"margin-bottom:25px" cellspacing=3D"0" cellpadding=3D"0" bor=
der=3D"0">
<tbody>
<tr>
<td style=3D"vertical-align:top;width:55px">
<img src=3D"https://meta-discourse.global.ssl.fastly.net/user_avata=
r/meta.discourse.org/techapj/45/3281.png" title=3D"techAPJ" style=3D"max-wi=
dth:100%" width=3D"45" height=3D"45">
</td>
<td>
<a href=3D"https://meta.discourse.org/users/techapj" style=3D"text-=
decoration:none;font-weight:bold;color:#006699;font-size:13px;font-family:&=
#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;color:#3b5998;text-d=
ecoration:none;font-weight:bold" target=3D"_blank">techAPJ</a><br>
<span style=3D"text-align:right;color:#999999;padding-right:5px;fon=
t-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;font-size:=
11px">November 28</span>
</td>
</tr>
<tr>
<td style=3D"padding-top:5px" colspan=3D"2">
<p style=3D"margin-top:0;border:0">Test reply.</p>
<p style=3D"margin-top:0;border:0">First paragraph.</p>
<p style=3D"margin-top:0;border:0">Second paragraph.</p>
</td>
</tr>
</tbody>
</table>
<div style=3D"color:#666">
<p>To respond, reply to this email or visit <a href=3D"https://meta.dis=
course.org/t/testing-default-email-replies/22638/3" style=3D"text-decoratio=
n:none;font-weight:bold;color:#006699;color:#666" target=3D"_blank">https:/=
/meta.discourse.org/t/testing-default-email-replies/22638/3</a> in your bro=
wser.</p>
</div>
<hr style=3D"background-color:#ddd;min-height:1px;border:1px;background-c=
olor:#ddd;min-height:1px;border:1px">
<h4>Previous Replies</h4>
<table style=3D"margin-bottom:25px" cellspacing=3D"0" cellpadding=3D"0" b=
order=3D"0">
<tbody>
<tr>
<td style=3D"vertical-align:top;width:55px">
<img src=3D"https://meta-discourse.global.ssl.fastly.net/user_avata=
r/meta.discourse.org/codinghorror/45/5297.png" title=3D"codinghorror" style=
=3D"max-width:100%" width=3D"45" height=3D"45">
</td>
<td>
<a href=3D"https://meta.discourse.org/users/codinghorror" style=3D"=
text-decoration:none;font-weight:bold;color:#006699;font-size:13px;font-fam=
ily:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;color:#3b5998;t=
ext-decoration:none;font-weight:bold" target=3D"_blank">codinghorror</a><br=
>
<span style=3D"text-align:right;color:#999999;padding-right:5px;fon=
t-family:&#39;lucida grande&#39;,tahoma,verdana,arial,sans-serif;font-size:=
11px">November 28</span>
</td>
</tr>
<tr>
<td style=3D"padding-top:5px" colspan=3D"2">
<p style=3D"margin-top:0;border:0">We&#39;re testing the latest GitHub emai=
l processing library which we are integrating now.</p>
<p style=3D"margin-top:0;border:0"><a href=3D"https://github.com/github/ema=
il_reply_parser" style=3D"text-decoration:none;font-weight:bold;color:#0066=
99" target=3D"_blank">https://github.com/github/email_reply_parser</a></p>
<p style=3D"margin-top:0;border:0">Go ahead and reply to this topic and I&#=
39;ll reply from various email clients for testing.</p>
</td>
</tr>
</tbody>
</table>
<hr style=3D"background-color:#ddd;min-height:1px;border:1px;background-col=
or:#ddd;min-height:1px;border:1px">
<div style=3D"color:#666">
<p>To respond, reply to this email or visit <a href=3D"https://meta.discour=
se.org/t/testing-default-email-replies/22638/3" style=3D"text-decoration:no=
ne;font-weight:bold;color:#006699;color:#666" target=3D"_blank">https://met=
a.discourse.org/t/testing-default-email-replies/22638/3</a> in your browser=
.</p>
</div>
<div style=3D"color:#666">
<p>To unsubscribe from these emails, visit your <a href=3D"https://meta.dis=
course.org/my/preferences" style=3D"text-decoration:none;font-weight:bold;c=
olor:#006699;color:#666" target=3D"_blank">user preferences</a>.</p>
</div>
</div>
</blockquote></div>
--001a1137c9285318bb0508f17bc5--
To stop receiving notifications for this particular topic, [click here](h=
ttps://bar.com/t/wat/1/unsubscribe). To unsubscribe from these emails, ch=
ange your [user preferences](https://bar.com/my/preferences).

11
spec/fixtures/emails/readonly.eml vendored Normal file
View file

@ -0,0 +1,11 @@
Return-Path: <readonly@bar.com>
From: Foo Bar <readonly@bar.com>
To: category@bar.com
Subject: This is a topic from a restricted user
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <33@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Hey, this is a topic from a restricted user ;)

Some files were not shown because too many files have changed in this diff Show more