2020-08-17 22:44:01 +02:00
<!-- Modal change mail server domain -->
2020-08-20 23:06:22 -07:00
< div class = "modal fade" id = "mailLocationModal" tabindex = "-1" role = "dialog" >
2020-08-17 22:44:01 +02:00
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header" >
2020-08-22 16:43:17 -07:00
< h4 class = "modal-title" > Change Email Server Location< / h4 >
2020-08-17 22:44:01 +02:00
< / div >
< div class = "modal-body" >
2020-08-22 16:43:17 -07:00
< div > Cloudron will make the necessary DNS changes across all the domains and restart the mail server.
2020-09-09 21:05:06 -07:00
Desktop & Mobile email clients have to be re-configured to use this new location as the IMAP and SMTP server.
2020-08-22 16:43:17 -07:00
< / div >
< br >
2020-08-20 23:06:22 -07:00
< form name = "mailLocationForm" role = "form" novalidate ng-submit = "mailLocation.submit()" autocomplete = "off" >
< div class = "form-group" ng-class = "{ 'has-error': (mailLocationForm.subdomain.$dirty && mailLocationForm.subdomain.$invalid) || (!mailLocationForm.subdomain.$dirty && mailLocation.error)}" >
2020-08-22 16:43:17 -07:00
< label class = "control-label" > Location< / label >
2020-08-20 23:06:22 -07:00
< div class = "has-error" ng-show = "mailLocation.error" > {{ mailLocation.error.message }}< / div >
< div class = "input-group form-inline" >
< input type = "text" class = "form-control" ng-model = "mailLocation.subdomain" id = "mailLocationLocationInput" name = "location" placeholder = "{{ 'Leave empty to use bare domain' }}" autofocus >
< div class = "input-group-btn" >
< button type = "button" class = "btn btn-default dropdown-toggle" data-toggle = "dropdown" >
< span > {{ (!mailLocation.subdomain ? '' : '.') + mailLocation.domain.domain }}< / span >
< span class = "caret" > < / span >
< / button >
< ul class = "dropdown-menu dropdown-menu-right" role = "menu" >
< li ng-repeat = "domain in domains" >
< a href = "" ng-click = "mailLocation.domain = domain" > {{ domain.domain }}< / a >
< / li >
< / ul >
< / div >
2020-08-17 22:44:01 +02:00
< / div >
< / div >
2020-08-20 23:06:22 -07:00
< p class = "small text-center text-warning" ng-show = "mailLocation.domain.provider === 'linode'" >
2020-09-09 10:08:13 -07:00
< b > Linode DNS average < a target = "_blank" ng-href = "https://docs.cloudron.io/domains/#linode-dns" > propagation time< / a > is 30 minutes.
2020-08-20 23:06:22 -07:00
Changing the location will take a while.< / b >
< br >
< / p >
< p class = "text-center" ng-show = "mailLocation.domain.provider === 'manual'" >
< b > Add an A record manually for {{ (!mailLocation.subdomain ? '' : '.') + mailLocation.domain.domain }} to this Cloudron's public IP< / b >
< br >
< / p >
< input class = "ng-hide" type = "submit" ng-disabled = "mailLocationForm.$invalid" / >
2020-08-17 22:44:01 +02:00
< / form >
< / div >
< div class = "modal-footer" >
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > Cancel< / button >
2020-08-20 23:06:22 -07:00
< button type = "button" class = "btn btn-success" ng-click = "mailLocation.submit()" ng-disabled = "mailLocationForm.$invalid || mailLocation.busy" > < i class = "fa fa-circle-notch fa-spin" ng-show = "mailLocation.busy" > < / i > Change< / button >
2020-08-17 22:44:01 +02:00
< / div >
< / div >
< / div >
< / div >
<!-- Modal change max email size -->
< div class = "modal fade" id = "maxEmailSizeChangeModal" tabindex = "-1" role = "dialog" >
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header" >
< h4 class = "modal-title" > Change Maximum Email Size< / h4 >
< / div >
< div class = "modal-body" >
2020-08-20 23:28:43 -07:00
< div > Changing the maximum email message size requires a restart of the mail server.< / div >
< br >
2020-08-17 22:44:01 +02:00
< form name = "maxEmailSizeChangeForm" role = "form" novalidate ng-submit = "maxEmailSize.submit()" autocomplete = "off" >
< div class = "form-group" >
< label class = "control-label" > Maximum size in megabytes : < b > {{ maxEmailSize.size | prettyDiskSize }}< / b > < / label >
2020-09-11 09:48:22 -07:00
< slider ng-model = "maxEmailSize.size" tooltip = "hide" min = "1048576" max = "1073741824" step = "1048576" > < / slider >
2020-08-17 22:44:01 +02:00
< / div >
< input class = "ng-hide" type = "submit" / >
< / form >
< / div >
< div class = "modal-footer" >
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > Cancel< / button >
2020-08-20 22:07:20 -07:00
< button type = "button" class = "btn btn-success" ng-click = "maxEmailSize.submit()" ng-disabled = "maxEmailSize.size === maxEmailSize.currentSize" > < i class = "fa fa-circle-notch fa-spin" ng-show = "maxEmailSize.busy" > < / i > Change< / button >
2020-08-17 22:44:01 +02:00
< / div >
< / div >
< / div >
< / div >
2020-08-22 13:01:25 -07:00
<!-- Modal change spam config -->
< div class = "modal fade" id = "spamConfigChangeModal" tabindex = "-1" role = "dialog" >
2020-08-17 22:44:01 +02:00
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header" >
2020-08-22 13:01:25 -07:00
< h4 class = "modal-title" > Spam Filtering< / h4 >
2020-08-17 22:44:01 +02:00
< / div >
< div class = "modal-body" >
2020-08-22 13:01:25 -07:00
< form name = "spamConfigChangeForm" role = "form" novalidate ng-submit = "spamConfig.submit()" autocomplete = "off" >
2020-08-17 22:44:01 +02:00
< div class = "form-group" >
2020-08-22 13:01:25 -07:00
< label class = "control-label" > Blacklisted addresses< / label >
< p class = "small" > Matched addresses will end up in the user's Spam folder. '*' and '?' glob patterns are supported.< / p >
< div class = "has-error" ng-show = "spamConfig.error.blacklist" > {{ spamConfig.error.blacklist }}< / div >
< textarea ng-model = "spamConfig.blacklist" placeholder = "Line separated email address patterns" name = "blacklist" class = "form-control" ng-class = "{ 'has-error': !spamConfigChangeForm.blacklist.$dirty && spamConfig.error.blacklist }" rows = "4" > < / textarea >
2020-08-17 22:44:01 +02:00
< / div >
< div class = "form-group" >
2020-09-09 23:19:37 -07:00
< label class = "control-label" > Custom Spamassassin Rules < sup > < a ng-href = "https://docs.cloudron.io/email/#custom-spam-filtering-rules" class = "help" target = "_blank" > < i class = "fa fa-question-circle" > < / i > < / a > < / sup > < / label >
2020-08-22 13:01:25 -07:00
< div class = "has-error" ng-show = "spamConfig.error.config" > {{ spamConfig.error.config }}< / div >
< textarea ng-model = "spamConfig.config" placeholder = "Custom Spamassassin Rules" class = "form-control" name = "config" ng-class = "{ 'has-error': !spamConfigChangeForm.config.$dirty && spamConfig.error.config }" rows = "4" > < / textarea >
2020-08-17 22:44:01 +02:00
< / div >
< input class = "ng-hide" type = "submit" / >
< / form >
< / div >
< div class = "modal-footer" >
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > Cancel< / button >
2020-08-22 13:01:25 -07:00
< button type = "button" class = "btn btn-success" ng-click = "spamConfig.submit()" > < i class = "fa fa-circle-notch fa-spin" ng-show = "spamConfig.busy" > < / i > Save< / button >
2020-08-17 22:44:01 +02:00
< / div >
< / div >
< / div >
< / div >
2020-02-12 14:51:06 +01:00
<!-- Test email -->
< div class = "modal fade" id = "testEmailModal" tabindex = "-1" role = "dialog" >
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header" >
< h4 class = "modal-title" > Send test email for < b > {{ testEmail.domain.domain }}< / b > < / h4 >
< / div >
< div class = "modal-body" >
< form name = "testEmailForm" role = "form" novalidate ng-submit = "testEmail.submit()" autocomplete = "off" >
< fieldset >
< p class = "has-error text-center" ng-show = "testEmail.error" > {{ testEmail.error.generic }}< / p >
< p > This will send a test email from < b > no-reply@{{testEmail.domain.domain}}< / b > to the address below.< / p >
< br / >
< div class = "form-group" ng-class = "{ 'has-error': testEmail.error.key }" >
< label class = "control-label" for = "inputTestEmailKey" > Email to< / label >
< input type = "text" class = "form-control" ng-model = "testEmail.mailTo" id = "inputTestMailTo" name = "mailTo" ng-disabled = "testEmail.busy" placeholder = "Email address" autofocus >
< / div >
< input class = "ng-hide" type = "submit" ng-disabled = "testEmailForm.$invalid" / >
< / fieldset >
< / form >
< / div >
< div class = "modal-footer " >
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > Cancel< / button >
< button type = "submit" class = "btn btn-outline btn-success pull-right" ng-click = "testEmail.submit()" ng-disabled = "testEmail.$invalid || testEmail.busy" >
< i class = "fa fa-circle-notch fa-spin" ng-show = "testEmail.busy" > < / i > < span > Send< / span >
< / button >
< / div >
< / div >
< / div >
< / div >
2020-03-06 23:11:26 -08:00
< div class = "content" >
2020-02-11 21:06:34 +01:00
< div class = "text-left" >
< h1 >
2020-02-11 22:07:58 -08:00
Mail Server
2020-02-11 21:06:34 +01:00
< / h1 >
< / div >
2020-02-11 22:07:58 -08:00
< div class = "text-left" >
< h3 > Domains< / h3 >
< / div >
2020-02-18 19:48:17 -08:00
< div class = "card card-large" style = "margin-bottom: 15px;" >
2020-02-11 21:06:34 +01:00
< div class = "row ng-hide" ng-hide = "ready" >
< div class = "col-lg-12 text-center" >
< h2 > < i class = "fa fa-circle-notch fa-spin" > < / i > < / h2 >
< / div >
< / div >
< div class = "row animateMeOpacity ng-hide" ng-show = "ready" >
< div class = "col-xs-12" >
< table class = "table table-hover" style = "margin: 0;" >
< thead >
< tr >
2020-02-12 14:10:21 +01:00
< th style = "width: 5%" > < / th >
2020-02-20 12:35:51 -08:00
< th style = "width: 30%" > Domain< / th >
< th style = "width: 60%" > Config< / th >
2020-11-11 22:50:57 +01:00
< th style = "width: 10%" > {{ 'main.actions' | tr }}< / th >
2020-02-11 21:06:34 +01:00
< / tr >
< / thead >
< tbody >
< tr ng-repeat = "domain in domains" >
2020-02-12 14:10:21 +01:00
< td >
< i class = "fa fa-circle" ng-style = "{ color: domain.statusOk ? '#27CE65' : '#d9534f' }" ng-show = "domain.status" > < / i >
< i class = "fa fa-circle-notch fa-spin" ng-hide = "domain.status" > < / i >
< / td >
2020-02-11 21:06:34 +01:00
< td class = "elide-table-cell no-padding" >
< a href = "/#/email/{{ domain.domain }}" class = "email-domain-list-item" > {{ domain.domain }}< / a >
< / td >
2020-02-20 12:35:51 -08:00
< td class = "elide-table-cell no-padding" >
< a href = "/#/email/{{ domain.domain }}" class = "email-domain-list-item" >
< span ng-show = "domain.inbound && domain.outbound" >
2020-06-02 14:34:38 +02:00
{{ domain.mailboxCount }} Mailbox(es) / Usage: {{ domain.usage | prettyByteSize }}
2020-02-20 12:35:51 -08:00
< / span >
< span ng-show = "!domain.inbound && domain.outbound" > Outbound only< / span >
< span ng-show = "!domain.inbound && !domain.outbound" > Disabled< / span >
< / a >
< / td >
2020-02-11 21:06:34 +01:00
< td class = "text-right no-wrap" >
2020-02-12 14:51:06 +01:00
< button class = "btn btn-xs btn-default" ng-click = "testEmail.show(domain)" uib-tooltip = "Send Test Email" > < i class = "fa fa-paper-plane" > < / i > < / button >
< a href = "/#/email/{{ domain.domain }}" class = "btn btn-xs btn-default" > < i class = "fa fa-pencil-alt" > < / i > < / a >
2020-02-11 21:06:34 +01:00
< / td >
< / tr >
< / tbody >
< / table >
< / div >
< / div >
< / div >
< br / >
2020-08-17 22:44:01 +02:00
< div class = "text-left" ng-show = "user.role === 'owner'" >
< h3 > Settings< / h3 >
< / div >
< div class = "card card-large" style = "margin-bottom: 15px;" >
2020-09-01 21:33:20 -07:00
< p > These settings are global and apply to all domains.< / p >
2020-08-17 22:44:01 +02:00
< div class = "row" >
< div class = "col-xs-6" >
2020-09-09 23:19:37 -07:00
< span class = "text-muted" > Mail server location< / span >
2020-08-17 22:44:01 +02:00
< / div >
< div class = "col-xs-6 text-right" >
2020-08-20 23:06:22 -07:00
< span > {{ mailLocation.currentLocation.subdomain + (!mailLocation.currentLocation.subdomain ? '' : '.') + mailLocation.currentLocation.domain.domain }}
2020-09-09 21:05:06 -07:00
< a ng-hide = "mailLocation.busy" href = "" ng-click = "mailLocation.show()" > < i class = "fa fa-edit text-small" > < / i > < / a > <!-- ng - disabled does not work for links -->
2020-08-20 23:06:22 -07:00
< / span >
2020-08-17 22:44:01 +02:00
< / div >
< div class = "col-xs-6" >
< span class = "text-muted" > Maximum email size< / span >
< / div >
< div class = "col-xs-6 text-right" >
2020-08-20 22:07:20 -07:00
< span > {{ maxEmailSize.currentSize | prettyDiskSize }} < a href = "" ng-click = "maxEmailSize.show()" > < i class = "fa fa-edit text-small" > < / i > < / a > < / span >
2020-08-17 22:44:01 +02:00
< / div >
< div class = "col-xs-6" >
2020-08-22 16:43:17 -07:00
< span class = "text-muted" > Spam filtering< / span >
2020-08-17 22:44:01 +02:00
< / div >
< div class = "col-xs-6 text-right" >
2020-08-22 19:34:06 -07:00
< span > {{ spamConfig.acl.blacklist.length }} address(es) blacklisted {{ spamConfig.customConfig ? '. Custom rules set.' : '.' }} < a href = "" ng-click = "spamConfig.show()" > < i class = "fa fa-edit text-small" > < / i > < / a > < / span >
2020-08-17 22:44:01 +02:00
< / div >
< / div >
2020-09-01 16:31:23 +02:00
< div class = "row" ng-show = "mailLocation.busy" >
< div class = "col-md-12" style = "margin-top: 10px;" >
Changing Email domain:
< div class = "progress progress-striped active animateMe" >
< div class = "progress-bar progress-bar-success" role = "progressbar" style = "width: {{ mailLocation.percent }}%" > < / div >
< / div >
< p > {{ mailLocation.message }}< / p >
< / div >
< / div >
2020-08-17 22:44:01 +02:00
< / div >
< br / >
2020-03-26 18:56:32 -07:00
< div class = "text-left" ng-show = "user.role === 'owner'" >
2020-03-25 20:13:45 -07:00
< h3 > Event Log< / h3 >
< / div >
2020-02-13 09:09:01 -08:00
2020-03-26 18:56:32 -07:00
< div class = "row" ng-show = "user.role === 'owner'" >
2020-03-25 20:13:45 -07:00
< div class = "col-md-12" >
< div class = "maillog-filter" >
< input class = "form-control" style = "width: 200px;" placeholder = "Search" type = "text" ng-model = "activity.search" ng-model-options = "{ debounce: 1000 }" ng-change = "activity.updateFilter()" / >
< multiselect ng-model = "activity.selectedTypes" ms-header = "All Events" options = "a.name for a in activityTypes" data-multiple = "true" ng-change = "activity.updateFilter(true)" filter-after-rows = "5" scroll-after-rows = "10" > < / multiselect >
< select class = "form-control" ng-model = "activity.pageItems" ng-options = "a.name for a in pageItemCount" ng-change = "activity.updateFilter(true)" > < / select >
< / div >
< div class = "pull-right" >
< button class = "btn btn-default btn-outline" ng-click = "activity.showPrevPage()" ng-disabled = "activity.busy || activity.currentPage <= 1" > < i class = "fa fa-angle-double-left" > < / i > prev< / button >
< button class = "btn btn-default btn-outline" ng-click = "activity.showNextPage()" ng-disabled = "activity.busy || activity.perPage > activity.eventLogs.length" > next < i class = "fa fa-angle-double-right" > < / i > < / button >
< / div >
< / div >
2020-02-11 21:06:34 +01:00
< / div >
2020-03-26 18:56:32 -07:00
< div class = "card card-large" style = "margin-top: 10px; margin-bottom: 15px;" ng-show = "user.role === 'owner'" >
2020-02-11 21:06:34 +01:00
< div class = "row ng-hide" ng-hide = "ready" >
< div class = "col-lg-12 text-center" >
< h2 > < i class = "fa fa-circle-notch fa-spin" > < / i > < / h2 >
< / div >
< / div >
< div class = "row animateMeOpacity ng-hide" ng-show = "ready" >
< div class = "col-xs-12" >
2020-02-11 22:07:58 -08:00
< table class = "table table-hover" style = "margin: 0;" >
< thead >
< tr >
2020-03-06 14:42:08 -08:00
< th style = "width: 5%" > <!-- Icon --> < / th >
2020-03-06 23:11:26 -08:00
< th style = "width: 20%" > Time< / th >
< th style = "width: 75%" > Details< / th >
2020-02-11 22:07:58 -08:00
< / tr >
< / thead >
2020-02-12 15:37:05 +01:00
< tbody ng-show = "activity.busy" >
< tr >
2020-03-06 14:42:08 -08:00
< td colspan = "4" class = "text-center" >
2020-02-12 15:37:05 +01:00
< i class = "fa fa-circle-notch fa-spin" > < / i >
< / td >
< / tr >
< / tbody >
2020-02-13 13:03:57 +01:00
< tbody ng-hide = "activity.eventLogs.length || activity.busy" >
2020-02-13 11:20:57 +01:00
< tr >
2020-03-06 14:42:08 -08:00
< td colspan = "4" class = "text-center" >
2020-02-18 19:48:17 -08:00
< br >
< br >
2020-02-13 11:20:57 +01:00
Event Log is empty.
2020-02-18 19:48:17 -08:00
< br >
< br >
2020-02-13 11:20:57 +01:00
< / td >
< / tr >
< / tbody >
2020-02-12 15:37:05 +01:00
< tbody ng-repeat = "eventlog in activity.eventLogs" ng-hide = "activity.busy" >
< tr ng-click = "activity.showEventLogDetails(eventlog)" class = "hand" >
< td class = "no-wrap" >
2020-03-06 14:42:08 -08:00
< i class = "fas fa-arrow-circle-left" ng-show = "eventlog.type === 'delivered'" uib-tooltip = "Outgoing" > < / i >
< i class = "fas fa-history" ng-show = "eventlog.type === 'deferred'" uib-tooltip = "Deferred" > < / i >
< i class = "fas fa-arrow-circle-right" ng-show = "eventlog.type === 'received'" uib-tooltip = "Incoming" > < / i >
< i class = "fas fa-align-justify" ng-show = "eventlog.type === 'queued'" uib-tooltip = "Queued" > < / i >
2020-02-18 19:48:17 -08:00
< i class = "fas fa-minus-circle" ng-show = "eventlog.type === 'denied'" uib-tooltip = "Denied" > < / i >
2020-03-06 14:42:08 -08:00
< i class = "fas fa-hand-paper" ng-show = "eventlog.type === 'bounce'" uib-tooltip = "Bounce" > < / i >
2020-09-09 22:24:38 -07:00
< i class = "fas fa-filter" ng-show = "eventlog.type === 'spam-learn'" uib-tooltip = "Spam filter trained" > < / i > < / td >
2020-03-06 14:42:08 -08:00
< td class = "no-wrap" > < span uib-tooltip = "{{ eventlog.ts | prettyLongDate }}" class = "arrow" > {{ eventlog.ts | prettyDate }}< / span > < / td >
2020-03-20 13:05:58 -07:00
< td >
< span ng-show = "eventlog.type === 'bounce'" > Sent bounce to {{ eventlog.mailFrom | prettyEmailAddresses }} for mail sent to {{ eventlog.rcptTo | prettyEmailAddresses }}. {{ eventlog.details.message || eventlog.details.reason }}< / span >
< span ng-show = "eventlog.type === 'deferred'" > Failed to deliver mail to {{ eventlog.rcptTo | prettyEmailAddresses }}. {{ eventlog.details.message || eventlog.details.reason }}. Will retry in {{ eventlog.details.delay }}s.< / span >
< span ng-show = "eventlog.type === 'queued'" >
< span ng-show = "eventlog.direction === 'inbound'" >
Incoming mail from {{ eventlog.mailFrom | prettyEmailAddresses }} to {{ eventlog.rcptTo | prettyEmailAddresses }}. Spam: {{ eventlog.details.spamStatus.indexOf('Yes,') === 0 ? 'Yes' : 'No' }}
< / span >
< span ng-show = "eventlog.direction === 'outbound'" >
Queued mail for delivery to {{ eventlog.rcptTo | prettyEmailAddresses }} from {{ eventlog.mailFrom | prettyEmailAddresses }}
< / span >
< / span >
< span ng-show = "eventlog.type === 'received'" > Saved mail from {{ eventlog.mailFrom | prettyEmailAddresses }} in mailbox {{ eventlog.rcptTo | prettyEmailAddresses }}< / span >
< span ng-show = "eventlog.type === 'delivered'" > Delivered mail to {{ eventlog.rcptTo | prettyEmailAddresses }} from {{ eventlog.mailFrom | prettyEmailAddresses }}< / span >
< span ng-show = "eventlog.type === 'denied'" > Connection from {{ eventlog.remote.ip }} denied. {{ eventlog.details.message || eventlog.details.reason }}< / span >
2020-03-06 14:42:08 -08:00
< span ng-show = "eventlog.type === 'spam-learn'" > Spam filter trained using mailbox content< / span >
2020-03-06 13:35:34 -08:00
< / td >
2020-02-12 15:37:05 +01:00
< / tr >
< tr ng-show = "activity.activeEventLog === eventlog" >
2020-02-12 23:17:24 -08:00
< td colspan = "6" >
2020-03-06 13:35:34 -08:00
< pre class = "eventlog-details" > {{ eventlog | json }}< / pre >
2020-02-12 15:37:05 +01:00
< / td >
< / tr >
2020-02-11 22:07:58 -08:00
< / tbody >
< / table >
2020-02-11 21:06:34 +01:00
2020-02-12 14:52:38 +01:00
< br / >
2020-02-11 21:06:34 +01:00
2020-02-12 14:52:38 +01:00
< a class = "btn btn-primary pull-right" href = "/logs.html?id=mail" target = "_blank" > Show Raw Logs< / a >
< / div >
2020-02-11 21:06:34 +01:00
< / div >
< / div >
2020-02-11 22:07:58 -08:00
2020-02-11 21:06:34 +01:00
< / div >