From cb4d5be072adbb6025d2f61f74f5389dfac76091 Mon Sep 17 00:00:00 2001 From: Ben Gotow Date: Mon, 28 Aug 2017 20:11:56 -0700 Subject: [PATCH] Fix send error handling --- .../stores/file-upload-store-spec.coffee | 6 --- app/src/flux/actions.es6 | 8 +--- app/src/flux/stores/draft-store.es6 | 1 + app/src/flux/tasks/send-draft-task.es6 | 43 ++++++++++++------- app/src/mailsync-process.es6 | 9 +++- app/src/nylas-env.es6 | 4 +- app/static/components/code-snippet.less | 15 ++++--- mailsync | 2 +- 8 files changed, 51 insertions(+), 37 deletions(-) diff --git a/app/spec_disabled/stores/file-upload-store-spec.coffee b/app/spec_disabled/stores/file-upload-store-spec.coffee index 612c3132b..b0b358514 100644 --- a/app/spec_disabled/stores/file-upload-store-spec.coffee +++ b/app/spec_disabled/stores/file-upload-store-spec.coffee @@ -130,12 +130,6 @@ xdescribe 'FileUploadStore', -> .then => expect(FileUploadStore._deleteUpload).toHaveBeenCalled() - describe "when a draft is sent", -> - it "should delete its uploads directory", -> - spyOn(FileUploadStore, '_deleteUploadsForId') - Actions.ensureMessageInSentSuccess({headerMessageId: '123'}) - expect(FileUploadStore._deleteUploadsForId).toHaveBeenCalledWith('123') - describe '_getFileStats', -> it 'returns the correct stats', -> spyOn(fs, 'stat').andCallFake (path, callback) -> diff --git a/app/src/flux/actions.es6 b/app/src/flux/actions.es6 index 77dc1d650..fed521e7d 100644 --- a/app/src/flux/actions.es6 +++ b/app/src/flux/actions.es6 @@ -396,12 +396,8 @@ class Actions { Recieves the id of the message that was sent */ - static draftDeliverySucceeded = ActionScopeGlobal; - static draftDeliveryFailed = ActionScopeGlobal; - - static ensureMessageInSentSuccess = ActionScopeGlobal; - - static sendManyDrafts = ActionScopeWindow; + static draftDeliverySucceeded = ActionScopeMainWindow; + static draftDeliveryFailed = ActionScopeMainWindow; /* Public: Destroys the draft with the given ID. This Action is handled by the {DraftStore}, diff --git a/app/src/flux/stores/draft-store.es6 b/app/src/flux/stores/draft-store.es6 index c525eaedb..40737612a 100644 --- a/app/src/flux/stores/draft-store.es6 +++ b/app/src/flux/stores/draft-store.es6 @@ -386,6 +386,7 @@ class DraftStore extends NylasStore { _onSendDraftFailed = ({headerMessageId, threadId, errorMessage, errorDetail}) => { this._draftsSending[headerMessageId] = false; this.trigger({headerMessageId}); + if (NylasEnv.isMainWindow()) { // We delay so the view has time to update the restored draft. If we // don't delay the modal may come up in a state where the draft looks diff --git a/app/src/flux/tasks/send-draft-task.es6 b/app/src/flux/tasks/send-draft-task.es6 index e27567347..6ca40490a 100644 --- a/app/src/flux/tasks/send-draft-task.es6 +++ b/app/src/flux/tasks/send-draft-task.es6 @@ -3,9 +3,10 @@ import url from 'url' import AccountStore from '../stores/account-store'; import Task from './task'; import Actions from '../actions'; -import SoundRegistry from '../../registries/sound-registry'; import Attributes from '../attributes'; import Message from '../models/message'; +import SoundRegistry from '../../registries/sound-registry'; +import {LocalizedErrorStrings} from '../../mailsync-process'; export default class SendDraftTask extends Task { @@ -17,9 +18,6 @@ export default class SendDraftTask extends Task { headerMessageId: Attributes.String({ modelKey: 'headerMessageId', }), - emitError: Attributes.Boolean({ - modelKey: 'emitError', - }), playSound: Attributes.Boolean({ modelKey: 'playSound', }), @@ -97,23 +95,36 @@ export default class SendDraftTask extends Task { } onError({key, debuginfo}) { - let message = key; + let errorMessage = null; + let errorDetail = null; + if (key === 'no-sent-folder') { - message = "We couldn't find a Sent folder in your account."; + errorMessage = "We couldn't find a Sent folder in your account."; + errorDetail = "In order to send mail through Merani, your email account must have a Sent Mail folder."; + } else if (key === 'no-trash-folder') { + errorMessage = "We couldn't find a Sent folder in your account."; + errorDetail = "In order to send mail through Merani, your email account must have a Trash folder."; + } else if (key === 'send-partially-failed') { + const [smtpError, emails] = debuginfo.split(':::'); + errorMessage = "We were unable to deliver this message to some recipients. Click 'See Details' for more information." + errorDetail = `We encountered an SMTP Gateway error that prevented this message from being delivered to all recipients. The message was only sent successfully to these recipients:\n${emails}\n\nError: ${LocalizedErrorStrings[smtpError]}`; + } else if (key === 'send-failed') { + errorMessage = `We were unable to deliver this message. ${LocalizedErrorStrings[debuginfo]}`; + errorDetail = `We encountered an SMTP error that prevented this message from being delivered:\n\n${LocalizedErrorStrings[debuginfo]}`; + } else { + errorMessage = "We were unable to deliver this message."; + errorDetail = `An unknown error occurred: ${JSON.stringify({key, debuginfo})}`; } - if (this.emitError) { - Actions.draftDeliveryFailed({ - threadId: this.draft.threadId, - headerMessageId: this.draft.headerMessageId, - errorMessage: message, - errorDetail: debuginfo, - }); - } + Actions.draftDeliveryFailed({ + threadId: this.draft.threadId, + headerMessageId: this.draft.headerMessageId, + errorMessage, + errorDetail, + }); Actions.recordUserEvent("Draft Sending Errored", { - error: message, key: key, - }) + }); } diff --git a/app/src/mailsync-process.es6 b/app/src/mailsync-process.es6 index ec6248923..f63fed41b 100644 --- a/app/src/mailsync-process.es6 +++ b/app/src/mailsync-process.es6 @@ -11,7 +11,7 @@ import fs from 'fs'; let Utils = null; -const LocalizedErrorStrings = { +export const LocalizedErrorStrings = { ErrorConnection: "Connection Error - Check that your internet connection is active.", ErrorInvalidAccount: "This account is invalid, or does not have an inbox or all folder.", ErrorTLSNotAvailable: "TLS Not Available", @@ -30,6 +30,13 @@ const LocalizedErrorStrings = { ErrorNeedsConnectToWebmail: "The server said you must sign in via your webmail.", ErrorNoValidServerFound: "No valid server found.", ErrorAuthenticationRequired: "Authentication required.", + + // sending related + ErrorSendMessageNotAllowed: "Sending is not enabled for this account.", + ErrorSendMessageIllegalAttachment: "The message contains an illegial attachment that is not allowed by the server.", + ErrorYahooSendMessageSpamSuspected: "The message has been blocked by Yahoo's outbound spam filter.", + ErrorYahooSendMessageDailyLimitExceeded: "The message has been blocked by Yahoo - you have exceeded your daily sending limit.", + ErrorNoSender: "The message has been blocked because no sender is configured.", }; export default class MailsyncProcess extends EventEmitter { diff --git a/app/src/nylas-env.es6 b/app/src/nylas-env.es6 index f339271c7..e47d425db 100644 --- a/app/src/nylas-env.es6 +++ b/app/src/nylas-env.es6 @@ -928,8 +928,8 @@ export default class NylasEnvConstructor { const {CodeSnippet} = require('nylas-component-kit'); Actions.openModal({ component: CodeSnippet({intro: message, code: detail, className: 'error-details'}), - height: 600, - width: 800, + width: 500, + height: 300, }); } }); diff --git a/app/static/components/code-snippet.less b/app/static/components/code-snippet.less index d2b51bb0a..da22962c5 100644 --- a/app/static/components/code-snippet.less +++ b/app/static/components/code-snippet.less @@ -1,13 +1,18 @@ .error-details { - height: 550px; - width: 750px; - margin: 5px 25px; + margin: 25px; display: flex; + position: absolute; flex-direction: column; + bottom: 0; + top: 0; + left: 0; + right: 0; textarea { resize: none; - width: 100%; - height: 100%; + border: 0; + background: rgba(0,0,0,0.05); + padding: 10px; + flex: 1; } } diff --git a/mailsync b/mailsync index 7bab242c1..4c3864bf2 160000 --- a/mailsync +++ b/mailsync @@ -1 +1 @@ -Subproject commit 7bab242c18fc293c612e29679f707583cdf7c101 +Subproject commit 4c3864bf22f706d67a0305313b226e7a71dd0ddd