Skip to main content
IHP provides email functionality via the ihp-mail package, built on top of mime-mail.

Setup

Add ihp-mail to your flake.nix:
haskellPackages = p: with p; [
    p.ihp
    cabal-install
    base
    wai
    ihp-mail  # Add this
];
Rebuild with devenv up or restart the development server.

Generating Email Templates

1

Open the Mail Code Generator

Access it from the IHP development tools.
2

Select controller and name

Choose the controller (e.g., Users) and enter the mail name (e.g., Confirmation).
3

Generate the template

Click Preview, then Generate to create Web/Mail/Users/Confirmation.hs.
Generated template:
module Web.Mail.Users.Confirmation where
import Web.View.Prelude
import IHP.MailPrelude

data ConfirmationMail = ConfirmationMail { user :: User }

instance BuildMail ConfirmationMail where
    subject = "Subject"
    to ConfirmationMail { .. } = Address { 
        addressName = Just "F L", 
        addressEmail = "[email protected]" 
    }
    from = "[email protected]"
    html ConfirmationMail { .. } = [hsx|
        Hello World
    |]

Customizing Email Templates

Subject Line

subject = "Confirm your Account"

Recipient

Use user data:
to ConfirmationMail { .. } = Address { 
    addressName = Just user.name, 
    addressEmail = user.email 
}

Sender

Reply-To Address

replyTo ConfirmationMail { .. } = Just Address { 
    addressName = Just "Support", 
    addressEmail = "[email protected]" 
}

Email Content

HTML version:
html ConfirmationMail { .. } = [hsx|
    Hey {user.name}, <br/>
    Thanks for signing up! Please confirm your account by following this link: <br/>
    <a href={urlTo ConfirmUserAction}>Confirm Account</a>
|]
Plain text version (recommended):
text ConfirmationMail { .. } = cs [trimming|
    Hey ${userName},

    Thanks for signing up! Please confirm your account by following this link:
    https://example.com/confirm
|]
    where
        userName = user.name
Providing a plain text version improves deliverability and accessibility. If omitted, IHP auto-generates one by stripping HTML tags.

Sending Emails

From a controller or script:
import IHP.Mail (sendMail)

action MyAction = do
    user <- fetch "..."
    sendMail ConfirmationMail { user }

Mail Server Configuration

Configure in Config/Config.hs:

Local Sendmail

import IHP.Mail.Types

config :: ConfigBuilder
config = do
    option Development
    option Sendmail

SMTP

import IHP.Mail.Types

config :: ConfigBuilder
config = do
    option $ SMTP
        { host = "smtp.myisp.com"
        , port = 2525
        , credentials = Just ("myusername", "hunter2")
        , encryption = TLS  -- or: Unencrypted, STARTTLS
        }

Environment Variables for SMTP

Recommended for production:
import IHP.Mail.Types
import Network.Socket (PortNumber)
import IHP.EnvVar

config :: ConfigBuilder
config = do
    smtpHost <- env @Text "SMTP_HOST"
    smtpPort <- env @PortNumber "SMTP_PORT"
    smtpEncryption <- env @SMTPEncryption "SMTP_ENCRYPTION"
    
    smtpUserMaybe <- envOrNothing "SMTP_USER"
    smtpPasswordMaybe <- envOrNothing "SMTP_PASSWORD"
    
    let smtpCredentials = case (smtpUserMaybe, smtpPasswordMaybe) of
            (Just user, Just password) -> Just (user, password)
            _ -> Nothing
    
    option $ SMTP
        { host = cs smtpHost
        , port = smtpPort
        , credentials = smtpCredentials
        , encryption = smtpEncryption
        }
In .envrc:
export SMTP_HOST="127.0.0.1"
export SMTP_PORT="1025"
export SMTP_ENCRYPTION="Unencrypted"
export SMTP_USER="username"
export SMTP_PASSWORD="password"

AWS SES

import IHP.Mail.Types

config :: ConfigBuilder
config = do
    option $ SES
        { accessKey = "YOUR_AWS_ACCESS_KEY"
        , secretKey = "YOUR_AWS_SECRET_KEY"
        , region = "eu-west-1"
        }

SendGrid

import IHP.Mail.Types

config :: ConfigBuilder
config = do
    option $ SendGrid
        { apiKey = "YOUR_SENDGRID_API_KEY"
        , category = Nothing  -- or: Just "mailcategory"
        }

MailHog (Development)

MailHog captures outgoing emails for testing:
  1. Install and run MailHog
  2. Configure SMTP to point to MailHog (default: 127.0.0.1:1025)
  3. View emails at http://0.0.0.0:8025/
# .envrc
export SMTP_HOST="127.0.0.1"
export SMTP_PORT="1025"
export SMTP_ENCRYPTION="Unencrypted"

Advanced Features

Custom Headers

headers ConfirmationMail { .. } =
    [ ("X-Mailer", "IHP Application")
    , ("In-Reply-To", "<[email protected]>")
    ]

Email Attachments

instance BuildMail ConfirmationMail where
    subject = "Your Receipt"
    to ConfirmationMail { .. } = Address { 
        addressName = Just user.name, 
        addressEmail = user.email 
    }
    from = "[email protected]"
    
    html ConfirmationMail { .. } = [hsx|
        Please find your receipt attached.
    |]
    
    attachments ConfirmationMail { .. } = [
        MailAttachment { 
            name = "receipt.pdf", 
            contentType = "application/pdf", 
            content = pdfContent 
        }
    ]
Remember to configure SPF and DKIM records for your domain to ensure reliable email delivery.

Build docs developers (and LLMs) love