Merged PR #528
Support for detecting MTA by its response. Message IDs are reconstructed based on detected MTA. Bugfixes for AWS. AWS now seems to work.
This commit is contained in:
parent
bbbe671d59
commit
3c72e778d9
6 changed files with 83 additions and 45 deletions
|
@ -93,6 +93,14 @@ export default class CUD extends Component {
|
|||
}
|
||||
|
||||
submitFormValuesMutator(data) {
|
||||
data.seconds = Number.parseInt(data.daysAfter) * 3600 * 24;
|
||||
|
||||
if (data.entity === Entity.SUBSCRIPTION) {
|
||||
data.event = data.subscriptionEvent;
|
||||
} else if (data.entity === Entity.CAMPAIGN) {
|
||||
data.event = data.campaignEvent;
|
||||
}
|
||||
|
||||
return filterData(data, ['name', 'description', 'entity', 'event', 'seconds', 'enabled', 'source_campaign']);
|
||||
}
|
||||
|
||||
|
@ -157,22 +165,14 @@ export default class CUD extends Component {
|
|||
this.disableForm();
|
||||
this.setFormStatusMessage('info', t('saving'));
|
||||
|
||||
const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url, data => {
|
||||
data.seconds = Number.parseInt(data.daysAfter) * 3600 * 24;
|
||||
|
||||
if (data.entity === Entity.SUBSCRIPTION) {
|
||||
data.event = data.subscriptionEvent;
|
||||
} else if (data.entity === Entity.CAMPAIGN) {
|
||||
data.event = data.campaignEvent;
|
||||
}
|
||||
});
|
||||
const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url);
|
||||
|
||||
if (submitResult) {
|
||||
if (this.props.entity) {
|
||||
if (submitAndLeave) {
|
||||
this.navigateToWithFlashMessage(`/campaigns/${this.props.campaign.id}/triggers`, 'success', t('triggerUpdated'));
|
||||
} else {
|
||||
await this.getFormValuesFromURL(`rest/triggers/${this.props.campaign.id}/${this.props.entity.id}`, ::this.getFormValuesMutator);
|
||||
await this.getFormValuesFromURL(`rest/triggers/${this.props.campaign.id}/${this.props.entity.id}`);
|
||||
this.enableForm();
|
||||
this.setFormStatusMessage('success', t('triggerUpdated'));
|
||||
}
|
||||
|
|
|
@ -57,18 +57,21 @@ export default class List extends Component {
|
|||
segmentId: PropTypes.string
|
||||
}
|
||||
|
||||
updateSegmentSelection(props) {
|
||||
componentDidMount() {
|
||||
this.populateFormValues({
|
||||
segment: props.segmentId || ''
|
||||
segment: this.props.segmentId || ''
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.updateSegmentSelection(this.props);
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.updateSegmentSelection(this.props);
|
||||
const segmentId = this.props.segmentId || '';
|
||||
|
||||
if (this.getFormValue('segment') !== segmentId) {
|
||||
// Populate is used here because it does not invoke onChange
|
||||
this.populateFormValues({
|
||||
segment: segmentId
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
@ -4,7 +4,16 @@ import React, {Component} from 'react';
|
|||
import {withTranslation} from '../lib/i18n';
|
||||
import {Title, withPageHelpers} from '../lib/page'
|
||||
import {Link} from 'react-router-dom'
|
||||
import {Button, ButtonRow, Form, FormSendMethod, InputField, withForm, withFormErrorHandlers} from '../lib/form';
|
||||
import {
|
||||
Button,
|
||||
ButtonRow,
|
||||
filterData,
|
||||
Form,
|
||||
FormSendMethod,
|
||||
InputField,
|
||||
withForm,
|
||||
withFormErrorHandlers
|
||||
} from '../lib/form';
|
||||
import {withAsyncErrorHandler, withErrorHandling} from '../lib/error-handling';
|
||||
import passwordValidator from '../../../shared/password-validator';
|
||||
import axios from '../lib/axios';
|
||||
|
@ -39,6 +48,10 @@ export default class Account extends Component {
|
|||
});
|
||||
}
|
||||
|
||||
submitFormValuesMutator(data) {
|
||||
return filterData(data, ['password']);
|
||||
}
|
||||
|
||||
@withAsyncErrorHandler
|
||||
async validateResetToken() {
|
||||
const params = this.props.match.params;
|
||||
|
@ -96,9 +109,7 @@ export default class Account extends Component {
|
|||
this.disableForm();
|
||||
this.setFormStatusMessage('info', t('resettingPassword'));
|
||||
|
||||
const submitSuccessful = await this.validateAndSendFormValuesToURL(FormSendMethod.POST, 'rest/password-reset', data => {
|
||||
delete data.password2;
|
||||
});
|
||||
const submitSuccessful = await this.validateAndSendFormValuesToURL(FormSendMethod.POST, 'rest/password-reset');
|
||||
|
||||
if (submitSuccessful) {
|
||||
this.navigateToWithFlashMessage('/login', 'success', t('passwordReset-1'));
|
||||
|
|
|
@ -78,6 +78,12 @@ export default class CUD extends Component {
|
|||
}
|
||||
|
||||
submitFormValuesMutator(data) {
|
||||
this.mailerTypes[data.mailer_type].beforeSave(data);
|
||||
if (!data.verpEnabled) {
|
||||
data.verp_hostname = null;
|
||||
data.verp_disable_sender_header = false;
|
||||
}
|
||||
|
||||
return filterData(data, ['name', 'description', 'from_email', 'from_email_overridable', 'from_name',
|
||||
'from_name_overridable', 'reply_to', 'reply_to_overridable', 'subject', 'subject_overridable', 'x_mailer',
|
||||
'verp_hostname', 'verp_disable_sender_header', 'mailer_type', 'mailer_settings', 'namespace']);
|
||||
|
@ -155,13 +161,7 @@ export default class CUD extends Component {
|
|||
this.disableForm();
|
||||
this.setFormStatusMessage('info', t('saving'));
|
||||
|
||||
const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url, data => {
|
||||
this.mailerTypes[data.mailer_type].beforeSave(data);
|
||||
if (!data.verpEnabled) {
|
||||
data.verp_hostname = null;
|
||||
data.verp_disable_sender_header = false;
|
||||
}
|
||||
});
|
||||
const submitResult = await this.validateAndSendFormValuesToURL(sendMethod, url);
|
||||
|
||||
if (submitResult) {
|
||||
if (this.props.entity) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const config = require('config');
|
||||
const log = require('./log');
|
||||
const mailers = require('./mailers');
|
||||
const knex = require('./knex');
|
||||
const subscriptions = require('../models/subscriptions');
|
||||
|
@ -20,8 +21,7 @@ const htmlToText = require('html-to-text');
|
|||
const {getPublicUrl} = require('./urls');
|
||||
const blacklist = require('../models/blacklist');
|
||||
const libmime = require('libmime');
|
||||
const shares = require('../models/shares')
|
||||
|
||||
const shares = require('../models/shares');
|
||||
|
||||
class CampaignSender {
|
||||
constructor() {
|
||||
|
@ -83,7 +83,7 @@ class CampaignSender {
|
|||
|
||||
const getOverridable = key => {
|
||||
return sendConfiguration[key];
|
||||
}
|
||||
};
|
||||
|
||||
const campaignAddress = [campaign.cid, list.cid, subscriptionGrouped.cid].join('.');
|
||||
|
||||
|
@ -95,7 +95,7 @@ class CampaignSender {
|
|||
replyTo: getOverridable('reply_to'),
|
||||
xMailer: sendConfiguration.x_mailer ? sendConfiguration.x_mailer : false,
|
||||
to: {
|
||||
name: tools.formatMessage(campaign, list, subscriptionGrouped, mergeTags, list.to_name, false),
|
||||
name: list.to_name === null ? undefined : tools.formatMessage(campaign, list, subscriptionGrouped, mergeTags, list.to_name, false),
|
||||
address: subscriptionGrouped.email
|
||||
},
|
||||
sender: useVerpSenderHeader ? campaignAddress + '@' + sendConfiguration.verp_hostname : false,
|
||||
|
@ -336,7 +336,7 @@ class CampaignSender {
|
|||
} else {
|
||||
return sendConfiguration[key] || '';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const mail = {
|
||||
from: {
|
||||
|
@ -346,7 +346,7 @@ class CampaignSender {
|
|||
replyTo: getOverridable('reply_to'),
|
||||
xMailer: sendConfiguration.x_mailer ? sendConfiguration.x_mailer : false,
|
||||
to: {
|
||||
name: tools.formatMessage(campaign, list, subscriptionGrouped, mergeTags, list.to_name, false),
|
||||
name: list.to_name === null ? undefined : tools.formatMessage(campaign, list, subscriptionGrouped, mergeTags, list.to_name, false),
|
||||
address: subscriptionGrouped.email
|
||||
},
|
||||
sender: this.useVerpSenderHeader ? campaignAddress + '@' + sendConfiguration.verp_hostname : false,
|
||||
|
@ -391,24 +391,49 @@ class CampaignSender {
|
|||
|
||||
let status;
|
||||
let response;
|
||||
let responseId;
|
||||
let responseId = null;
|
||||
try {
|
||||
const info = await mailer.sendMassMail(mail);
|
||||
status = SubscriptionStatus.SUBSCRIBED;
|
||||
|
||||
/*
|
||||
ZoneMTA
|
||||
log.verbose('CampaignSender', `response: ${info.response} messageId: ${info.messageId}`);
|
||||
|
||||
let match;
|
||||
if ((match = info.response.match(/^250 Message queued as ([0-9a-f]+)$/))) {
|
||||
/*
|
||||
ZoneMTA
|
||||
info.response: 250 Message queued as 1691ad7f7ae00080fd
|
||||
info.messageId: <e65c9386-e899-7d01-b21e-ec03c3a9d9b4@sathyasai.org>
|
||||
*/
|
||||
response = info.response;
|
||||
responseId = match[1];
|
||||
|
||||
Postal Mail Server
|
||||
} else if ((match = info.messageId.match(/^<([^>@]*)@.*amazonses\.com>$/))) {
|
||||
/*
|
||||
AWS SES
|
||||
info.response: 0102016ad2244c0a-955492f2-9194-4cd1-bef9-70a45906a5a7-000000
|
||||
info.messageId: <0102016ad2244c0a-955492f2-9194-4cd1-bef9-70a45906a5a7-000000@eu-west-1.amazonses.com>
|
||||
*/
|
||||
response = info.response;
|
||||
responseId = match[1];
|
||||
|
||||
} else if (info.response.match(/^250 OK$/) && (match = info.messageId.match(/^<([^>]*)>$/))) {
|
||||
/*
|
||||
Postal Mail Server
|
||||
info.response: 250 OK
|
||||
info.messageId: <xxxxxxxxx@xxx.xx> (postal messageId)
|
||||
*/
|
||||
*/
|
||||
response = info.response;
|
||||
responseId = match[1];
|
||||
|
||||
} else {
|
||||
/*
|
||||
Fallback - Mailtrain v1 behavior
|
||||
*/
|
||||
response = info.response || info.messageId;
|
||||
responseId = response.split(/\s+/).pop();
|
||||
}
|
||||
|
||||
console.log(`response: ${info.response} messageId: ${info.messageId}`);
|
||||
response = info.response || info.messageId;
|
||||
responseId = info.messageId.replace(/(^<|>$)/g, "") || response.split(/\s+/).pop();
|
||||
|
||||
await knex('campaigns').where('id', campaign.id).increment('delivered');
|
||||
} catch (err) {
|
||||
|
@ -417,6 +442,7 @@ class CampaignSender {
|
|||
await knex('campaigns').where('id', campaign.id).increment('delivered').increment('bounced');
|
||||
}
|
||||
|
||||
|
||||
const now = new Date();
|
||||
|
||||
if (campaign.type === CampaignType.REGULAR || campaign.type === CampaignType.RSS_ENTRY) {
|
||||
|
@ -443,4 +469,4 @@ class CampaignSender {
|
|||
}
|
||||
}
|
||||
|
||||
module.exports = CampaignSender;
|
||||
module.exports = CampaignSender;
|
|
@ -13,8 +13,6 @@ const uploads = multer();
|
|||
|
||||
|
||||
router.postAsync('/aws', async (req, res) => {
|
||||
console.log(req.body);
|
||||
|
||||
if (typeof req.body === 'string') {
|
||||
req.body = JSON.parse(req.body);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue