chore(mail): add setting to reroute all mails (letters are generated but not sent)

This commit is contained in:
Steffen Jost 2023-01-17 13:34:37 +01:00
parent 18767aa968
commit 9da61c10b5
6 changed files with 42 additions and 27 deletions

View File

@ -182,6 +182,7 @@ instance YesodMail UniWorX where
envelopeFromAddress = getsYesod $ view _appMailEnvelopeFrom envelopeFromAddress = getsYesod $ view _appMailEnvelopeFrom
mailObjectIdDomain = getsYesod $ view _appMailObjectDomain mailObjectIdDomain = getsYesod $ view _appMailObjectDomain
useReplyToInstead = getsYesod $ view _appMailUseReplyToInstead useReplyToInstead = getsYesod $ view _appMailUseReplyToInstead
mailRerouteTo = getsYesod $ view _appMailRerouteTo
mailDateTZ = return appTZ mailDateTZ = return appTZ
mailSmtp act = do mailSmtp act = do
pool <- maybe (throwM MailNotAvailable) return =<< getsYesod appSmtpPool pool <- maybe (throwM MailNotAvailable) return =<< getsYesod appSmtpPool

View File

@ -51,7 +51,7 @@ userAddress :: User -> Address
userAddress User{userEmail, userDisplayName} = Address (Just userDisplayName) $ CI.original userEmail userAddress User{userEmail, userDisplayName} = Address (Just userDisplayName) $ CI.original userEmail
-- |Send an email to the given UserId or to all registered Supervisor with rerouteNotifications == True -- | Send an email to the given UserId or to all registered Supervisor with rerouteNotifications == True
userMailT :: ( MonadHandler m userMailT :: ( MonadHandler m
, HandlerSite m ~ UniWorX , HandlerSite m ~ UniWorX
, MonadThrow m , MonadThrow m

View File

@ -78,7 +78,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(..), YamlValue, maybeMonoid, insertAssoc, maybeT, guardM, adjustAssoc) import Utils (MsgRendererS(..), MonadSecretBox(..), YamlValue, maybeMonoid, insertAssoc, maybeM, maybeT, guardM, adjustAssoc)
import Utils.Lens.TH import Utils.Lens.TH
import Control.Lens hiding (from) import Control.Lens hiding (from)
@ -272,6 +272,9 @@ class Yesod site => YesodMail site where
useReplyToInstead :: (MonadHandler m, HandlerSite m ~ site) => m Bool useReplyToInstead :: (MonadHandler m, HandlerSite m ~ site) => m Bool
useReplyToInstead = return True -- not changeing the sender is the save choice useReplyToInstead = return True -- not changeing the sender is the save choice
mailRerouteTo :: (MonadHandler m, HandlerSite m ~ site) => m (Maybe Address)
mailRerouteTo = return Nothing -- all mail will be sent to this address instead, if set (for test-instances)
mailDateTZ :: (MonadHandler m, HandlerSite m ~ site) => m TZ mailDateTZ :: (MonadHandler m, HandlerSite m ~ site) => m TZ
mailDateTZ = return utcTZ mailDateTZ = return utcTZ
@ -325,19 +328,23 @@ defMailT :: ( MonadHandler m
-> m a -> m a
defMailT ls (MailT mailC) = do defMailT ls (MailT mailC) = do
fromAddress <- defaultFromAddress fromAddress <- defaultFromAddress
(ret, mail, smtpData) <- runRWST mailC ls (emptyMail fromAddress) (ret, mail0, smtpData) <- runRWST mailC ls (emptyMail fromAddress)
mail' <- maybeT (return mail) $ do mail1 <- maybeT (return mail0) $ do
guardM useReplyToInstead -- if sender must be fixed within ObjectIdDomain, use replyTo instead guardM useReplyToInstead -- if sender must be fixed within ObjectIdDomain, use replyTo instead
domain <- mailObjectIdDomain domain <- mailObjectIdDomain
let sender = mail ^. _mailFrom let sender = mail0 ^. _mailFrom
isdomainaddress = (Text.isInfixOf `on` Text.toCaseFold) domain (sender ^. _addressEmail) -- not sure how to use CI.mk and isInfixOf here isdomainaddress = (Text.isInfixOf `on` Text.toCaseFold) domain (sender ^. _addressEmail) -- not sure how to use CI.mk and isInfixOf here
$logDebugS "Mail" $ "Use ReplyTo instead of Sender: " <> tshow isdomainaddress <> " From was: " <> renderAddress sender <> " From is: " <> renderAddress fromAddress $logDebugS "Mail" $ "Use ReplyTo instead of Sender: " <> tshow isdomainaddress <> " From was: " <> renderAddress sender <> " From is: " <> renderAddress fromAddress
guard isdomainaddress -- allowing foreign senders might be Fraport specific; maybe remove this guard guard isdomainaddress -- allowing foreign senders might be Fraport specific; maybe remove this guard
return $ mail return $ mail0
& _mailFrom .~ fromAddress & _mailFrom .~ fromAddress
& _mailReplyTo .~ sender & _mailReplyTo .~ sender
mail'' <- liftIO $ LBS.toStrict <$> renderMail' mail' let switchRecipient rerouteTo = return $ mail1
$logDebugS "Mail" $ "Rendered mail:\n" <> decodeUtf8 mail'' & _mailTo .~ [rerouteTo]
& Mime.addPart [plainPart $ LT.fromStrict $ "Due to setting 'mail-reroute-to', this mail was diverted; it would have been sent to: " <> tshow (mail1 ^. _mailTo)]
mail2 <- maybeM (return mail1) switchRecipient mailRerouteTo
mail3 <- liftIO $ LBS.toStrict <$> renderMail' mail2
$logDebugS "Mail" $ "Rendered mail:\n" <> decodeUtf8 mail3
ret <$ case smtpData of ret <$ case smtpData of
MailSmtpData{ smtpEnvelopeFrom = Last Nothing } -> throwM MailNoSenderSpecified MailSmtpData{ smtpEnvelopeFrom = Last Nothing } -> throwM MailNoSenderSpecified
MailSmtpData{ smtpRecipients } MailSmtpData{ smtpRecipients }
@ -349,7 +356,7 @@ defMailT ls (MailT mailC) = do
liftIO $ SMTP.sendMail liftIO $ SMTP.sendMail
returnPath returnPath
recipients recipients
mail'' mail3
conn conn

View File

@ -136,6 +136,7 @@ data AppSettings = AppSettings
, appMailFrom , appMailFrom
, appMailSender , appMailSender
, appMailSupport :: Address , appMailSupport :: Address
, appMailRerouteTo :: Maybe Address
, appMailUseReplyToInstead :: Bool , appMailUseReplyToInstead :: Bool
, appJobWorkers :: Natural , appJobWorkers :: Natural
, appJobFlushInterval :: Maybe NominalDiffTime , appJobFlushInterval :: Maybe NominalDiffTime
@ -656,6 +657,7 @@ instance FromJSON AppSettings where
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" appMailSupport <- o .: "mail-support"
appMailRerouteTo <- o .:? "mail-reroute-to"
appJobWorkers <- o .: "job-workers" appJobWorkers <- o .: "job-workers"
appJobFlushInterval <- o .:? "job-flush-interval" appJobFlushInterval <- o .:? "job-flush-interval"

View File

@ -842,8 +842,6 @@ toNothingS = const Nothing
-- null2nothing other = other -- null2nothing other = other
-- | Swap 'Nothing' for 'Just' and vice versa -- | Swap 'Nothing' for 'Just' and vice versa
-- This belongs into Module 'Utils' but we have a weird cyclic
-- dependency
flipMaybe :: b -> Maybe a -> Maybe b flipMaybe :: b -> Maybe a -> Maybe b
flipMaybe x Nothing = Just x flipMaybe x Nothing = Just x
flipMaybe _ (Just _) = Nothing flipMaybe _ (Just _) = Nothing

View File

@ -453,7 +453,7 @@ sendEmailOrLetter recipient letter = do
let msg = "Notification failed for " <> tshow encRecipient <> ". PDF generation failed: "<> cropText err <> "For Notification: " <> tshow pjid let msg = "Notification failed for " <> tshow encRecipient <> ". PDF generation failed: "<> cropText err <> "For Notification: " <> tshow pjid
$logErrorS "LETTER" msg $logErrorS "LETTER" msg
return False return False
Right pdf | preferPost -> -- send letter Right pdf | preferPost -> -- send printed letter
runDB (sendLetter pdf pjid{ pjiRecipient = Just svr}) >>= \case runDB (sendLetter pdf pjid{ pjiRecipient = Just svr}) >>= \case
Left err -> do Left err -> do
encRecipient :: CryptoUUIDUser <- encrypt svr encRecipient :: CryptoUUIDUser <- encrypt svr
@ -557,21 +557,28 @@ encryptPDF pw bs = over _Left (decodeUtf8 . LBS.toStrict) . exit2either <$> read
-- | Internal only, use `sendLetter` instead -- | Internal only, use `sendLetter` instead
lprPDF :: (MonadHandler m, HasAppSettings (HandlerSite m)) => Text -> LBS.ByteString -> m (Either Text Text) lprPDF :: (MonadHandler m, HasAppSettings (HandlerSite m)) => Text -> LBS.ByteString -> m (Either Text Text)
lprPDF jb bs = do lprPDF jb bs = do
lprServerArg <- $cachedHereBinary ("lprServer"::Text) getLprServerArg mbLprServerArg <- $cachedHereBinary ("lprServer"::Text) getLprServerArg
let pc = setStdin (byteStringInput bs) $ case mbLprServerArg of
proc "lpr" $ Nothing -> return $ Right "Print command ignored due to setting 'mail-reroute-to' being set."
jobname ++ -- -J jobname -- a name for job identification at printing site Just lprServerArg -> do
[ lprServerArg -- -P queue@hostname:port let pc = setStdin (byteStringInput bs) $
, "-" -- read from stdin proc "lpr" $
] jobname ++ -- -J jobname -- a name for job identification at printing site
jobname | null jb = [] [ lprServerArg -- -P queue@hostname:port
| otherwise = ["-J " <> jb'] , "-" -- read from stdin
jb' = T.unpack $ sanitizeCmdArg jb ]
exit2either <$> readProcess' pc jobname | null jb = []
| otherwise = ["-J " <> jb']
jb' = T.unpack $ sanitizeCmdArg jb
exit2either <$> readProcess' pc
where where
getLprServerArg = do getLprServerArg = do
LprConf{..} <- getsYesod $ view _appLprConf rerouteMail <- getsYesod $ view _appMailRerouteTo
return $ "-P " <> lprQueue <> "@" <> lprHost <> ":" <> show lprPort case rerouteMail of
Just _ -> return Nothing
Nothing -> do
LprConf{..} <- getsYesod $ view _appLprConf
return . Just $ "-P " <> lprQueue <> "@" <> lprHost <> ":" <> show lprPort
{- -- Variant without caching {- -- Variant without caching