Add support for direct SSL/TLS (non-STARTTLS) SMTP connections.
- Add support for TLS in `smtppool` (v0.4.0) and upgrade the lib. - Change `tls_enabled: bool` in the settings table to string `tls_type: STARTTLS|TLS|none` and on the settings UI. - Add DB migrations and schema changes to apply the field change. Closes #504.
This commit is contained in:
parent
b48a15cfa3
commit
dd061f56d4
22 changed files with 52 additions and 11 deletions
|
@ -68,7 +68,7 @@ type settings struct {
|
|||
MaxMsgRetries int `json:"max_msg_retries"`
|
||||
IdleTimeout string `json:"idle_timeout"`
|
||||
WaitTimeout string `json:"wait_timeout"`
|
||||
TLSEnabled bool `json:"tls_enabled"`
|
||||
TLSType string `json:"tls_type"`
|
||||
TLSSkipVerify bool `json:"tls_skip_verify"`
|
||||
} `json:"smtp"`
|
||||
|
||||
|
|
|
@ -81,13 +81,17 @@
|
|||
<div class="column">
|
||||
<b-field grouped>
|
||||
<b-field :label="$t('settings.mailserver.tls')" expanded
|
||||
:message="$t('settings.mailserver.tlsHelp')">
|
||||
<b-switch v-model="item.tls_enabled" name="item.tls_enabled" />
|
||||
:message="$t('settings.mailserver.tlsHelp')" label-position="on-border">
|
||||
<b-select v-model="item.tls_type" name="items.tls_type">
|
||||
<option value="none">{{ $t('globals.states.off') }}</option>
|
||||
<option value="STARTTLS">STARTTLS</option>
|
||||
<option value="TLS">SSL/TLS</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<b-field :label="$t('settings.mailserver.skipTLS')" expanded
|
||||
:message="$t('settings.mailserver.skipTLSHelp')">
|
||||
<b-switch v-model="item.tls_skip_verify"
|
||||
:disabled="!item.tls_enabled" name="item.tls_skip_verify" />
|
||||
:disabled="item.tls_type === 'none'" name="item.tls_skip_verify" />
|
||||
</b-field>
|
||||
</b-field>
|
||||
</div>
|
||||
|
@ -188,7 +192,7 @@ export default Vue.extend({
|
|||
max_msg_retries: 2,
|
||||
idle_timeout: '15s',
|
||||
wait_timeout: '5s',
|
||||
tls_enabled: true,
|
||||
tls_type: 'STARTTLS',
|
||||
tls_skip_verify: false,
|
||||
});
|
||||
|
||||
|
|
2
go.mod
2
go.mod
|
@ -15,7 +15,7 @@ require (
|
|||
github.com/knadh/go-pop3 v0.3.0
|
||||
github.com/knadh/goyesql/v2 v2.1.2
|
||||
github.com/knadh/koanf v1.2.3
|
||||
github.com/knadh/smtppool v0.3.1
|
||||
github.com/knadh/smtppool v0.4.0
|
||||
github.com/knadh/stuffbin v1.1.0
|
||||
github.com/labstack/echo/v4 v4.6.1
|
||||
github.com/labstack/gommon v0.3.1 // indirect
|
||||
|
|
2
go.sum
2
go.sum
|
@ -84,6 +84,8 @@ github.com/knadh/koanf v1.2.3 h1:2Rkr0YhhYk+4QEOm800Q3Pu0Wi87svTxM6uuEb4WhYw=
|
|||
github.com/knadh/koanf v1.2.3/go.mod h1:xpPTwMhsA/aaQLAilyCCqfpEiY1gpa160AiCuWHJUjY=
|
||||
github.com/knadh/smtppool v0.3.1 h1:teF/Lp/8wInTq2gTAOnmxPIcX9yPY6o4n57qf0qdJfM=
|
||||
github.com/knadh/smtppool v0.3.1/go.mod h1:3DJHouXAgPDBz0kC50HukOsdapYSwIEfJGwuip46oCA=
|
||||
github.com/knadh/smtppool v0.4.0 h1:335iXPwZ6katJVhauV4O6e8uPvvPmO6YLrfDQhb6UvE=
|
||||
github.com/knadh/smtppool v0.4.0/go.mod h1:3DJHouXAgPDBz0kC50HukOsdapYSwIEfJGwuip46oCA=
|
||||
github.com/knadh/stuffbin v1.1.0 h1:f5S5BHzZALjuJEgTIOMC9NidEnBJM7Ze6Lu1GHR/lwU=
|
||||
github.com/knadh/stuffbin v1.1.0/go.mod h1:yVCFaWaKPubSNibBsTAJ939q2ABHudJQxRWZWV5yh+4=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
"globals.months.7": "Črc",
|
||||
"globals.months.8": "Srp",
|
||||
"globals.months.9": "Zář",
|
||||
"globals.states.off": "Off",
|
||||
"globals.terms.analytics": "Analytics",
|
||||
"globals.terms.bounce": "Nedoručitelnost | Případy nedoručitelnosti",
|
||||
"globals.terms.bounces": "Případy nedoručitelnosti",
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
"globals.months.7": "Jul",
|
||||
"globals.months.8": "Aug",
|
||||
"globals.months.9": "Sep",
|
||||
"globals.states.off": "Off",
|
||||
"globals.terms.analytics": "Analytics",
|
||||
"globals.terms.bounce": "Bounce | Bounces",
|
||||
"globals.terms.bounces": "Bounces",
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
"globals.months.7": "Jul",
|
||||
"globals.months.8": "Aug",
|
||||
"globals.months.9": "Sep",
|
||||
"globals.states.off": "Off",
|
||||
"globals.terms.analytics": "Analytics",
|
||||
"globals.terms.bounce": "Bounce | Bounces",
|
||||
"globals.terms.bounces": "Bounces",
|
||||
|
@ -360,7 +361,7 @@
|
|||
"settings.mailserver.skipTLS": "Skip TLS verification",
|
||||
"settings.mailserver.skipTLSHelp": "Skip hostname check on the TLS certificate.",
|
||||
"settings.mailserver.tls": "TLS",
|
||||
"settings.mailserver.tlsHelp": "Enable STARTTLS.",
|
||||
"settings.mailserver.tlsHelp": "TLS/SSL encryption. STARTTLS is commonly used.",
|
||||
"settings.mailserver.username": "Username",
|
||||
"settings.mailserver.waitTimeout": "Wait timeout",
|
||||
"settings.mailserver.waitTimeoutHelp": "Time to wait for new activity on a connection before closing it and removing it from the pool (s for second, m for minute).",
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
"globals.months.7": "Julio",
|
||||
"globals.months.8": "Agosto",
|
||||
"globals.months.9": "Setiembre",
|
||||
"globals.states.off": "Off",
|
||||
"globals.terms.analytics": "Analitica",
|
||||
"globals.terms.bounce": "Rebote | Rebotes",
|
||||
"globals.terms.bounces": "Rebotes",
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
"globals.months.7": "juil.",
|
||||
"globals.months.8": "août",
|
||||
"globals.months.9": "sept.",
|
||||
"globals.states.off": "Off",
|
||||
"globals.terms.analytics": "Analyses",
|
||||
"globals.terms.bounce": "Rebond | Rebonds",
|
||||
"globals.terms.bounces": "Rebonds",
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
"globals.months.7": "Jul",
|
||||
"globals.months.8": "Aug",
|
||||
"globals.months.9": "Sep",
|
||||
"globals.states.off": "Off",
|
||||
"globals.terms.analytics": "Analitika",
|
||||
"globals.terms.bounce": "Visszapattanó | Visszapattanók",
|
||||
"globals.terms.bounces": "Visszapattanók",
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
"globals.months.7": "Lug",
|
||||
"globals.months.8": "Ago",
|
||||
"globals.months.9": "Set",
|
||||
"globals.states.off": "Off",
|
||||
"globals.terms.analytics": "Analytics",
|
||||
"globals.terms.bounce": "Bounce | Bounces",
|
||||
"globals.terms.bounces": "Bounces",
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
"globals.months.7": "ജൂലൈ",
|
||||
"globals.months.8": "ഓഗസ്റ്റ്",
|
||||
"globals.months.9": "സെപ്റ്റംബർ",
|
||||
"globals.states.off": "Off",
|
||||
"globals.terms.analytics": "Analytics",
|
||||
"globals.terms.bounce": "Bounce | Bounces",
|
||||
"globals.terms.bounces": "Bounces",
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
"globals.months.7": "Jul",
|
||||
"globals.months.8": "Aug",
|
||||
"globals.months.9": "Sep",
|
||||
"globals.states.off": "Off",
|
||||
"globals.terms.analytics": "Analytics",
|
||||
"globals.terms.bounce": "Bounce | Bounces",
|
||||
"globals.terms.bounces": "Bounces",
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
"globals.months.7": "Lip",
|
||||
"globals.months.8": "Sie",
|
||||
"globals.months.9": "Wrz",
|
||||
"globals.states.off": "Off",
|
||||
"globals.terms.analytics": "Analityka",
|
||||
"globals.terms.bounce": "Odbicie | Obicia",
|
||||
"globals.terms.bounces": "Odbicia",
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
"globals.months.7": "Jul",
|
||||
"globals.months.8": "Ago",
|
||||
"globals.months.9": "Set",
|
||||
"globals.states.off": "Off",
|
||||
"globals.terms.analytics": "Analytics",
|
||||
"globals.terms.bounce": "Bounce | Bounces",
|
||||
"globals.terms.bounces": "Bounces",
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
"globals.months.7": "Jul",
|
||||
"globals.months.8": "Ago",
|
||||
"globals.months.9": "Set",
|
||||
"globals.states.off": "Off",
|
||||
"globals.terms.analytics": "Analytics",
|
||||
"globals.terms.bounce": "Bounce | Bounces",
|
||||
"globals.terms.bounces": "Bounces",
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
"globals.months.7": "Iul",
|
||||
"globals.months.8": "Aug",
|
||||
"globals.months.9": "Sep",
|
||||
"globals.states.off": "Off",
|
||||
"globals.terms.analytics": "Analitice",
|
||||
"globals.terms.bounce": "Respins | Respinse",
|
||||
"globals.terms.bounces": "Respinse",
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
"globals.months.7": "Июл",
|
||||
"globals.months.8": "Авг",
|
||||
"globals.months.9": "Сен",
|
||||
"globals.states.off": "Off",
|
||||
"globals.terms.analytics": "Analytics",
|
||||
"globals.terms.bounce": "Bounce | Bounces",
|
||||
"globals.terms.bounces": "Bounces",
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
"globals.months.7": "Tem",
|
||||
"globals.months.8": "Aug",
|
||||
"globals.months.9": "Eyl",
|
||||
"globals.states.off": "Off",
|
||||
"globals.terms.analytics": "Analytics",
|
||||
"globals.terms.bounce": "Bounce | Bounces",
|
||||
"globals.terms.bounces": "Bounces",
|
||||
|
|
|
@ -18,7 +18,7 @@ type Server struct {
|
|||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
AuthProtocol string `json:"auth_protocol"`
|
||||
TLSEnabled bool `json:"tls_enabled"`
|
||||
TLSType string `json:"tls_type"`
|
||||
TLSSkipVerify bool `json:"tls_skip_verify"`
|
||||
EmailHeaders map[string]string `json:"email_headers"`
|
||||
|
||||
|
@ -57,13 +57,18 @@ func New(servers ...Server) (*Emailer, error) {
|
|||
s.Opt.Auth = auth
|
||||
|
||||
// TLS config.
|
||||
if s.TLSEnabled {
|
||||
if s.TLSType != "none" {
|
||||
s.TLSConfig = &tls.Config{}
|
||||
if s.TLSSkipVerify {
|
||||
s.TLSConfig.InsecureSkipVerify = s.TLSSkipVerify
|
||||
} else {
|
||||
s.TLSConfig.ServerName = s.Host
|
||||
}
|
||||
|
||||
// SSL/TLS, not STARTTLS.
|
||||
if s.TLSType == "TLS" {
|
||||
s.Opt.SSL = true
|
||||
}
|
||||
}
|
||||
|
||||
pool, err := smtppool.New(s.Opt)
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
// V2_1_0 performs the DB migrations for v.2.1.0.
|
||||
func V2_1_0(db *sqlx.DB, fs stuffbin.FileSystem, ko *koanf.Koanf) error {
|
||||
// Insert into appearance related settings.
|
||||
if _, err := db.Exec(`
|
||||
INSERT INTO settings (key, value) VALUES
|
||||
('appearance.admin.custom_css', '""'),
|
||||
|
@ -19,5 +20,19 @@ func V2_1_0(db *sqlx.DB, fs stuffbin.FileSystem, ko *koanf.Koanf) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Replace all `tls_enabled: true/false` keys in the `smtp` settings JSON array
|
||||
// with the new field `tls_type: STARTTLS|TLS|none`.
|
||||
// The `tls_enabled` key is removed.
|
||||
if _, err := db.Exec(`
|
||||
UPDATE settings SET value = s.updated
|
||||
FROM (
|
||||
SELECT JSONB_AGG(
|
||||
JSONB_SET(v - 'tls_enabled', '{tls_type}', (CASE WHEN v->>'tls_enabled' = 'true' THEN '"STARTTLS"' ELSE '"none"' END)::JSONB)
|
||||
) AS updated FROM settings, JSONB_ARRAY_ELEMENTS(value) v WHERE key = 'smtp'
|
||||
) s WHERE key = 'smtp';
|
||||
`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -207,8 +207,8 @@ INSERT INTO settings (key, value) VALUES
|
|||
('upload.s3.bucket_type', '"public"'),
|
||||
('upload.s3.expiry', '"14d"'),
|
||||
('smtp',
|
||||
'[{"enabled":true, "host":"smtp.yoursite.com","port":25,"auth_protocol":"cram","username":"username","password":"password","hello_hostname":"","max_conns":10,"idle_timeout":"15s","wait_timeout":"5s","max_msg_retries":2,"tls_enabled":true,"tls_skip_verify":false,"email_headers":[]},
|
||||
{"enabled":false, "host":"smtp2.yoursite.com","port":587,"auth_protocol":"plain","username":"username","password":"password","hello_hostname":"","max_conns":10,"idle_timeout":"15s","wait_timeout":"5s","max_msg_retries":2,"tls_enabled":false,"tls_skip_verify":false,"email_headers":[]}]'),
|
||||
'[{"enabled":true, "host":"smtp.yoursite.com","port":25,"auth_protocol":"cram","username":"username","password":"password","hello_hostname":"","max_conns":10,"idle_timeout":"15s","wait_timeout":"5s","max_msg_retries":2,"tls_type":"STARTTLS","tls_skip_verify":false,"email_headers":[]},
|
||||
{"enabled":false, "host":"smtp.gmail.com","port":465,"auth_protocol":"login","username":"username@gmail.com","password":"password","hello_hostname":"","max_conns":10,"idle_timeout":"15s","wait_timeout":"5s","max_msg_retries":2,"tls_type":"TLS","tls_skip_verify":false,"email_headers":[]}]'),
|
||||
('messengers', '[]'),
|
||||
('bounce.enabled', 'false'),
|
||||
('bounce.webhooks_enabled', 'false'),
|
||||
|
|
Loading…
Reference in a new issue