diff --git a/config/config.go b/config/config.go index 9ca0a041..a527e761 100644 --- a/config/config.go +++ b/config/config.go @@ -1,12 +1,14 @@ package config import ( + "crypto/tls" "encoding/json" "fmt" "log" "os" "path/filepath" "strings" + "sync" "github.com/google/uuid" "github.com/zalando/go-keyring" @@ -29,6 +31,11 @@ const ( DateFormatEU = "DD/MM/YYYY HH:MM" ) +type SessionCache struct { + once sync.Once + cache tls.ClientSessionCache +} + // Account stores the configuration for a single email account. type Account struct { ID string `json:"id"` @@ -46,6 +53,8 @@ type Account struct { // regardless of which address they were delivered to. CatchAll bool `json:"catch_all,omitempty"` + SC *SessionCache `json:"-"` // "-" prevents the SessionCache from being saved to config.json + // Custom server settings (used when ServiceProvider is "custom") IMAPServer string `json:"imap_server,omitempty"` IMAPPort int `json:"imap_port,omitempty"` @@ -229,6 +238,14 @@ func (a *Account) GetSMTPServer() string { } } +func (a *Account) GetClientSessionCache() tls.ClientSessionCache { + a.SC.once.Do(func() { + a.SC.cache = tls.NewLRUClientSessionCache(64) + }) + + return a.SC.cache +} + // GetSMTPPort returns the SMTP port for the account. func (a *Account) GetSMTPPort() int { switch a.ServiceProvider { @@ -580,6 +597,7 @@ func LoadConfig() (*Config, error) { Password: legacyConfig.Password, ServiceProvider: legacyConfig.ServiceProvider, FetchEmail: legacyConfig.Email, + SC: &SessionCache{}, }, }, } @@ -631,6 +649,7 @@ func LoadConfig() (*Config, error) { POP3Server: rawAcc.POP3Server, POP3Port: rawAcc.POP3Port, CatchAll: rawAcc.CatchAll, + SC: &SessionCache{}, } // Validate PGPKeySource diff --git a/config/config_test.go b/config/config_test.go index e7974d18..d60b2c84 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -32,6 +32,7 @@ func TestSaveAndLoadConfig(t *testing.T) { Password: "supersecret", ServiceProvider: "gmail", SendAsEmail: "alias@example.com", + SC: &SessionCache{}, }, { ID: "test-id-2", @@ -44,6 +45,7 @@ func TestSaveAndLoadConfig(t *testing.T) { SMTPServer: "smtp.custom.com", SMTPPort: 587, CatchAll: true, + SC: &SessionCache{}, }, }, } diff --git a/fetcher/fetcher.go b/fetcher/fetcher.go index 0b83c489..ad61b12d 100644 --- a/fetcher/fetcher.go +++ b/fetcher/fetcher.go @@ -29,6 +29,7 @@ import ( "github.com/emersion/go-message/mail" "github.com/emersion/go-pgpmail" "github.com/floatpane/matcha/config" + "github.com/floatpane/matcha/internal/loglevel" "go.mozilla.org/pkcs7" "golang.org/x/text/encoding" "golang.org/x/text/encoding/ianaindex" @@ -376,6 +377,11 @@ func connectWithOptions(account *config.Account, extraOpts *imapclient.Options) ServerName: imapServer, InsecureSkipVerify: account.Insecure, MinVersion: tls.VersionTLS12, + ClientSessionCache: account.GetClientSessionCache(), + VerifyConnection: func(cs tls.ConnectionState) error { + loglevel.Debugf("IMAP TLS connection resumed: %t", cs.DidResume) + return nil + }, }, } if extraOpts != nil { diff --git a/main.go b/main.go index 9462de21..844460be 100644 --- a/main.go +++ b/main.go @@ -383,6 +383,7 @@ func (m *mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { POP3Server: msg.POP3Server, POP3Port: msg.POP3Port, MaildirPath: msg.MaildirPath, + SC: &config.SessionCache{}, } if msg.Provider == "custom" || msg.Protocol == "pop3" { @@ -428,6 +429,7 @@ func (m *mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { POP3Server: msg.POP3Server, POP3Port: msg.POP3Port, MaildirPath: msg.MaildirPath, + SC: &config.SessionCache{}, } if msg.Provider == "custom" || msg.Protocol == "pop3" { diff --git a/sender/sender.go b/sender/sender.go index 4df43a93..c40bec2f 100644 --- a/sender/sender.go +++ b/sender/sender.go @@ -25,6 +25,7 @@ import ( "github.com/emersion/go-pgpmail" "github.com/floatpane/matcha/clib" "github.com/floatpane/matcha/config" + "github.com/floatpane/matcha/internal/loglevel" "github.com/floatpane/matcha/pgp" "github.com/yuin/goldmark" "github.com/yuin/goldmark/ast" @@ -660,6 +661,11 @@ func SendEmail(account *config.Account, to, cc, bcc []string, subject, plainBody ServerName: smtpServer, InsecureSkipVerify: account.Insecure, MinVersion: tls.VersionTLS12, + ClientSessionCache: account.GetClientSessionCache(), + VerifyConnection: func(cs tls.ConnectionState) error { + loglevel.Debugf("SMTP TLS connection resumed: %t", cs.DidResume) + return nil + }, } var c *smtp.Client @@ -870,10 +876,16 @@ func SendCalendarReply(account *config.Account, to []string, subject, plainBody // Send via SMTP addr := fmt.Sprintf("%s:%d", smtpServer, smtpPort) + tlsConfig := &tls.Config{ ServerName: smtpServer, InsecureSkipVerify: account.Insecure, MinVersion: tls.VersionTLS12, + ClientSessionCache: account.GetClientSessionCache(), + VerifyConnection: func(cs tls.ConnectionState) error { + loglevel.Debugf("SMTP TLS connection resumed: %t", cs.DidResume) + return nil + }, } var c *smtp.Client