src/Pure/General/mail.scala
changeset 78829 58315c8a5cc4
child 78855 6fdcd6c8c97a
equal deleted inserted replaced
78828:032b6186fddc 78829:58315c8a5cc4
       
     1 /*  Title:      Pure/General/mail.scala
       
     2     Author:     Fabian Huch, TU Muenchen
       
     3 
       
     4 Support for sending text mails via SMTP.
       
     5 */
       
     6 
       
     7 package isabelle
       
     8 
       
     9 
       
    10 import java.util.Properties as JProperties
       
    11 import javax.mail.internet.{InternetAddress, MimeMessage}
       
    12 import javax.mail.{AuthenticationFailedException, Authenticator, Message, MessagingException, PasswordAuthentication, Transport as JTransport, Session as JSession}
       
    13 
       
    14 
       
    15 object Mail {
       
    16   /* validated addresses */
       
    17 
       
    18   final class Address private[Mail](rep: String) {
       
    19     override def toString: String = rep
       
    20   }
       
    21 
       
    22   val default_address: Address = address("user@localhost")
       
    23   def address(s: String): Address =
       
    24     Exn.capture(new InternetAddress(s).validate()) match {
       
    25       case Exn.Res(_) => new Address(s)
       
    26       case _ => error("Invalid mail address: " + quote(s))
       
    27     }
       
    28 
       
    29 
       
    30   /* smtp server */
       
    31 
       
    32   enum Transport {
       
    33     case Plaintext extends Transport
       
    34     case SSL(protocol: String = "TLSv1.2") extends Transport
       
    35     case STARTTLS extends Transport
       
    36   }
       
    37 
       
    38   class Server (
       
    39     sender: Address,
       
    40     smtp_host: String,
       
    41     smtp_port: Int = 587,
       
    42     user: String = "",
       
    43     password: String = "",
       
    44     transport: Transport = Transport.SSL()
       
    45   ) {
       
    46     def use_auth: Boolean = user.nonEmpty && password.nonEmpty
       
    47 
       
    48     private def mail_session: JSession = {
       
    49       val props = new JProperties()
       
    50       props.setProperty("mail.smtp.host", smtp_host)
       
    51       props.setProperty("mail.smtp.port", smtp_port.toString)
       
    52       props.setProperty("mail.smtp.auth", use_auth.toString)
       
    53 
       
    54       transport match {
       
    55         case Transport.SSL(protocol) =>
       
    56           props.setProperty("mail.smtp.ssl.enable", "true")
       
    57          props.setProperty("mail.smtp.ssl.protocols", protocol)
       
    58         case Transport.STARTTLS =>
       
    59           props.setProperty("mail.smtp.starttls.enable", "true")
       
    60         case Transport.Plaintext =>
       
    61       }
       
    62 
       
    63       val authenticator = new Authenticator() {
       
    64         override def getPasswordAuthentication = new PasswordAuthentication(user, password)
       
    65       }
       
    66       JSession.getDefaultInstance(props, authenticator)
       
    67     }
       
    68 
       
    69     def defined: Boolean = smtp_host.nonEmpty
       
    70     def check(): Unit = {
       
    71       val transport = mail_session.getTransport("smtp")
       
    72       try {
       
    73         transport.connect(smtp_host, smtp_port, user, password)
       
    74         transport.close()
       
    75       }
       
    76       catch {
       
    77         case exn: Throwable => error("Could not connect to SMTP server: " + exn.getMessage)
       
    78       }
       
    79     }
       
    80 
       
    81     def send(mail: Mail): Unit = {
       
    82       val from_address = mail.from_address.getOrElse(sender)
       
    83       val from =
       
    84         if (mail.from_name.isEmpty) new InternetAddress(from_address.toString)
       
    85         else new InternetAddress(from_address.toString, mail.from_name)
       
    86 
       
    87       val message = new MimeMessage(mail_session)
       
    88       message.setFrom(from)
       
    89       message.setSender(new InternetAddress(sender.toString))
       
    90       message.setSubject(mail.subject)
       
    91       message.setText(mail.content, "UTF-8")
       
    92       message.setSentDate(new java.util.Date())
       
    93 
       
    94       for (recipient <- mail.recipients) {
       
    95         message.addRecipient(Message.RecipientType.TO, new InternetAddress(recipient.toString))
       
    96       }
       
    97 
       
    98       try { JTransport.send(message) }
       
    99       catch { case exn: Throwable => error("Sending mail failed: " + exn.getMessage) }
       
   100     }
       
   101   }
       
   102 }
       
   103 
       
   104 case class Mail(
       
   105   subject: String,
       
   106   recipients: List[Mail.Address],
       
   107   content: String,
       
   108   from_address: Option[Mail.Address] = None,
       
   109   from_name: String = "")