diff --git a/misc/mail-notify b/misc/mail-notify
new file mode 100755
index 0000000..2d5ae88
--- /dev/null
+++ b/misc/mail-notify
@@ -0,0 +1,54 @@
+#!/usr/bin/env amm
+
+import $ivy.`com.sun.mail:javax.mail:1.6.2`
+import $ivy.`com.lihaoyi::os-lib:0.7.1`
+
+import javax.mail.internet._
+import os.up
+
+// paths
+
+val icon = "/usr/share/icons/Adwaita/48x48/actions/mail-message-new.png"
+val cacheFile = envPath("XDG_CACHE_HOME", os.home/".cache") / "seen-mails"
+val maildir = envPath("MAILDIR", os.home/"Mail")
+
+
+case class MailInfo(from: String, subject: String, mailbox: String)
+object MailInfo {
+  def fromPath(p: os.Path, maildir: os.Path) = {
+    val msg = readMessage(p)
+    MailInfo(
+      msg.getFrom.head.asInstanceOf[InternetAddress].getPersonal.replace("&", "&"),
+      msg.getSubject.replace("&", "&"),
+      (p/up/up relativeTo maildir).toString
+    )
+  }
+}
+
+val session = javax.mail.Session.getDefaultInstance(new java.util.Properties)
+
+def readMessage(path: os.Path) = {
+  val in = os.read.inputStream(path)
+  new MimeMessage(session, in)
+}
+
+def envPath(envVar: String, default: os.Path): os.Path =
+  sys.env.get(envVar).map(s => os.Path(s)).getOrElse(default)
+
+
+val cache = if (os.exists(cacheFile)) os.read.lines(cacheFile).toSet else Set.empty[String]
+
+val newMailPaths = os.proc("fd", "-t", "f" ,".*:2,[PRTDF]*$", "-a", maildir)
+  .call().out.lines.toSet
+
+val unseenMailPaths = newMailPaths &~ cache
+
+val unseenMails = unseenMailPaths.map(p => MailInfo.fromPath(os.Path(p), maildir))
+
+if (!unseenMails.isEmpty) {
+  val markup = unseenMails.map(msg => s"<b>${msg.from}:</b> ${msg.subject}<br>").mkString
+  println(markup)
+  os.proc("notify-send", s"--icon=$icon", "Mails", markup).call()
+}
+
+os.write.over(cacheFile, newMailPaths.mkString("", "\n", "\n"))