fix(mail): better separation of sender/from/envelope-from

This commit is contained in:
Gregor Kleen 2020-11-04 17:21:40 +01:00
parent 875f002aaa
commit 0dbf4f8bde
6 changed files with 17 additions and 14 deletions

View File

@ -18,6 +18,7 @@ mail-from:
mail-object-domain: "_env:MAILOBJECT_DOMAIN:localhost" mail-object-domain: "_env:MAILOBJECT_DOMAIN:localhost"
mail-verp: mail-verp:
separator: "_env:VERP_SEPARATOR:+" separator: "_env:VERP_SEPARATOR:+"
prefix: "_env:VERP_PREFIX:bounce"
mail-support: mail-support:
name: "_env:MAILSUPPORT_NAME:" name: "_env:MAILSUPPORT_NAME:"
email: "_env:MAILSUPPORT:uni2work@ifi.lmu.de" email: "_env:MAILSUPPORT:uni2work@ifi.lmu.de"

View File

@ -187,6 +187,7 @@ instance YesodAuthPersist UniWorX where
instance YesodMail UniWorX where instance YesodMail UniWorX where
defaultFromAddress = getsYesod $ view _appMailFrom defaultFromAddress = getsYesod $ view _appMailFrom
envelopeFromAddress = getsYesod $ view _appMailEnvelopeFrom
mailObjectIdDomain = getsYesod $ view _appMailObjectDomain mailObjectIdDomain = getsYesod $ view _appMailObjectDomain
mailDateTZ = return appTZ mailDateTZ = return appTZ
mailSmtp act = do mailSmtp act = do
@ -199,7 +200,7 @@ instance YesodMail UniWorX where
void setMailObjectIdRandom void setMailObjectIdRandom
sentMailSentAt <- liftIO getCurrentTime sentMailSentAt <- liftIO getCurrentTime
setDate sentMailSentAt setDate sentMailSentAt
replaceMailHeader "Sender" . Just =<< getsYesod (view $ _appMailFrom . _addressEmail) replaceMailHeader "Sender" . Just =<< getsYesod (view $ _appMailSender . to renderAddress)
(mRes, smtpData) <- listen mail (mRes, smtpData) <- listen mail
@ -217,7 +218,7 @@ instance YesodMail UniWorX where
-> do -> do
verpSecret <- getsYesod appVerpSecret verpSecret <- getsYesod appVerpSecret
let bounceSecret = BounceSecret . Crypto.kmacGetDigest $ kmaclazy ("bounce" :: ByteString) verpSecret $ Binary.encode mContent let bounceSecret = BounceSecret . Crypto.kmacGetDigest $ kmaclazy ("bounce" :: ByteString) verpSecret $ Binary.encode mContent
verpAddr = l <> Text.singleton verpSeparator <> toPathPiece bounceSecret <> "@" <> d verpAddr = l <> Text.singleton verpSeparator <> verpPrefix <> "." <> toPathPiece bounceSecret <> "@" <> d
return ( smtpData' <> mempty { smtpEnvelopeFrom = Last $ Just verpAddr } return ( smtpData' <> mempty { smtpEnvelopeFrom = Last $ Just verpAddr }
, Just bounceSecret , Just bounceSecret
) )

View File

@ -70,7 +70,7 @@ import qualified Data.Text.Lazy.Builder as LTB
import qualified Data.ByteString.Lazy as LBS import qualified Data.ByteString.Lazy as LBS
import qualified Data.ByteString as BS import qualified Data.ByteString as BS
import Utils (MsgRendererS(..), MonadSecretBox(..), maybeT, YamlValue) import Utils (MsgRendererS(..), MonadSecretBox(..), YamlValue)
import Utils.Lens.TH import Utils.Lens.TH
import Control.Lens hiding (from) import Control.Lens hiding (from)
@ -108,8 +108,6 @@ import Data.Universe.Instances.Reverse ()
import Data.Universe.Instances.Reverse.JSON () import Data.Universe.Instances.Reverse.JSON ()
import Data.Universe.Instances.Reverse.Hashable () import Data.Universe.Instances.Reverse.Hashable ()
import Control.Monad.Trans.Maybe (MaybeT(..))
import Data.CaseInsensitive (CI) import Data.CaseInsensitive (CI)
import qualified Data.CaseInsensitive as CI import qualified Data.CaseInsensitive as CI
@ -227,6 +225,8 @@ instance Exception MailException
class Yesod site => YesodMail site where class Yesod site => YesodMail site where
defaultFromAddress :: (MonadHandler m, HandlerSite m ~ site) => m Address defaultFromAddress :: (MonadHandler m, HandlerSite m ~ site) => m Address
defaultFromAddress = Address Nothing . ("yesod@" <>) . pack <$> liftIO getHostName defaultFromAddress = Address Nothing . ("yesod@" <>) . pack <$> liftIO getHostName
envelopeFromAddress :: (MonadHandler m, HandlerSite m ~ site) => m Text
envelopeFromAddress = addressEmail <$> defaultFromAddress
mailObjectIdDomain :: (MonadHandler m, HandlerSite m ~ site) => m Text mailObjectIdDomain :: (MonadHandler m, HandlerSite m ~ site) => m Text
mailObjectIdDomain = pack <$> liftIO getHostName mailObjectIdDomain = pack <$> liftIO getHostName
@ -542,10 +542,7 @@ setDate time = do
getMailSmtpData :: (MonadHandler m, YesodMail (HandlerSite m), MonadThrow m) => MailT m MailSmtpData getMailSmtpData :: (MonadHandler m, YesodMail (HandlerSite m), MonadThrow m) => MailT m MailSmtpData
getMailSmtpData = execWriterT $ do getMailSmtpData = execWriterT $ do
Address _ from <- lift . maybeT (throwM MailNoSenderSpecified) $ asum from <- envelopeFromAddress
[ MaybeT . preuses (_mailHeader "Sender") $ fromString . unpack
, use _mailFrom
]
recps <- lift $ Set.fromList . concat <$> forM [_mailTo, _mailCc, _mailBcc] use recps <- lift $ Set.fromList . concat <$> forM [_mailTo, _mailCc, _mailBcc] use
tell $ mempty tell $ mempty

View File

@ -100,7 +100,7 @@ instance FromJSON NotificationSettings where
derivePersistFieldJSON ''NotificationSettings derivePersistFieldJSON ''NotificationSettings
newtype BounceSecret = BounceSecret (Digest (SHAKE256 128)) newtype BounceSecret = BounceSecret (Digest (SHAKE128 64))
deriving (Eq, Ord, Read, Show, Lift, Generic, Typeable) deriving (Eq, Ord, Read, Show, Lift, Generic, Typeable)
deriving newtype ( PersistField, PersistFieldSql deriving newtype ( PersistField, PersistFieldSql
, Hashable, NFData , Hashable, NFData

View File

@ -111,10 +111,12 @@ data AppSettings = AppSettings
, appSessionTokenExpiration :: Maybe NominalDiffTime , appSessionTokenExpiration :: Maybe NominalDiffTime
, appSessionTokenEncoding :: JwtEncoding , appSessionTokenEncoding :: JwtEncoding
, appMailFrom :: Address
, appMailObjectDomain :: Text , appMailObjectDomain :: Text
, appMailVerp :: VerpMode , appMailVerp :: VerpMode
, appMailRetainSent :: Maybe NominalDiffTime , appMailRetainSent :: Maybe NominalDiffTime
, appMailEnvelopeFrom :: Text
, appMailFrom
, appMailSender
, appMailSupport :: Address , appMailSupport :: Address
, appJobWorkers :: Natural , appJobWorkers :: Natural
, appJobFlushInterval :: Maybe NominalDiffTime , appJobFlushInterval :: Maybe NominalDiffTime
@ -303,7 +305,7 @@ data TokenBucketConf = TokenBucketConf
} deriving (Eq, Ord, Show, Generic, Typeable) } deriving (Eq, Ord, Show, Generic, Typeable)
data VerpMode = VerpNone data VerpMode = VerpNone
| Verp { verpSeparator :: Char } | Verp { verpPrefix :: Text, verpSeparator :: Char }
deriving (Eq, Show, Read, Generic) deriving (Eq, Show, Read, Generic)
deriveJSON defaultOptions deriveJSON defaultOptions
@ -460,10 +462,12 @@ instance FromJSON AppSettings where
appIpFromHeader <- o .: "ip-from-header" appIpFromHeader <- o .: "ip-from-header"
appMailFrom <- o .: "mail-from" appMailFrom <- o .: "mail-from"
appMailEnvelopeFrom <- o .:? "mail-envelope-from" .!= addressEmail appMailFrom
appMailSender <- o .:? "mail-sender" .!= appMailFrom
appMailSupport <- o .: "mail-support"
appMailObjectDomain <- o .: "mail-object-domain" appMailObjectDomain <- o .: "mail-object-domain"
appMailVerp <- fromMaybe VerpNone . join <$> (o .:? "mail-verp" <|> pure Nothing) appMailVerp <- fromMaybe VerpNone . join <$> (o .:? "mail-verp" <|> pure Nothing)
appMailRetainSent <- o .: "mail-retain-sent" appMailRetainSent <- o .: "mail-retain-sent"
appMailSupport <- o .: "mail-support"
appJobWorkers <- o .: "job-workers" appJobWorkers <- o .: "job-workers"
appJobFlushInterval <- o .:? "job-flush-interval" appJobFlushInterval <- o .:? "job-flush-interval"

View File

@ -150,5 +150,5 @@ instance FromJSON VerpSecret where
instance ClusterSetting 'ClusterVerpSecret where instance ClusterSetting 'ClusterVerpSecret where
type ClusterSettingValue 'ClusterVerpSecret = VerpSecret type ClusterSettingValue 'ClusterVerpSecret = VerpSecret
initClusterSetting _ = liftIO $ Crypto.getRandomBytes 32 initClusterSetting _ = liftIO $ Crypto.getRandomBytes 16
knownClusterSetting _ = ClusterVerpSecret knownClusterSetting _ = ClusterVerpSecret