forked from finagle/finagle-smtp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEmailMessage.scala
111 lines (89 loc) · 3.23 KB
/
EmailMessage.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package io.github.finagle.smtp
import java.text.SimpleDateFormat
import java.util.{Calendar, Date}
import com.twitter.util.{Try, TimeFormat, Time}
/** Defines email address */
private[smtp] class MailingAddress(val local: String, val domain: String) {
val mailbox: String = {
if (isEmpty) ""
else local + "@" + domain
}
val isEmpty: Boolean = local.isEmpty && domain.isEmpty
val nonEmpty: Boolean = !isEmpty
}
/** Factory for mailing addresses. */
object MailingAddress {
/**
* Checks if address is syntactically correct according to
* [[http://tools.ietf.org/search/rfc5321#section-4.1.2]] (for example, [email protected])
*/
def correct(address: String): Boolean = Try {
val Array(local, domain) = address split "@"
require(local.nonEmpty)
require(domain.nonEmpty)
}.isReturn
def correct(addrs: Seq[String]): Boolean = addrs.map(MailingAddress.correct(_)).contains(false)
/**
* Creates a [[io.github.finagle.smtp.MailingAddress]] from the given string.
* The given string representation of a mailbox should be syntactically correct
* (according to [[http://tools.ietf.org/search/rfc5321#section-4.1.2]], for
* example: [email protected]). If it is not, an IllegalArgumentException is thrown.
*
* @param address String representation of a mailbox
*/
def apply(address: String): MailingAddress = {
if (MailingAddress.correct(address)) {
val Array(local, domain) = address split "@"
new MailingAddress(local, domain)
}
else throw new IllegalArgumentException("Incorrect mailbox syntax: %s" format address)
}
/** An empty mailing address */
val empty: MailingAddress = new MailingAddress("","")
/**
* Creates a string representation of given list of mailboxes.
*
* @param addrs The addresses in the list
* @return String containing string representation of given
* addresses divided with a comma.
*/
def mailboxList(addrs: Seq[MailingAddress]): String = {
val mailboxes = addrs collect {
case addr: MailingAddress if addr.nonEmpty => addr.mailbox
}
mailboxes mkString ","
}
}
/**
* Defines fields and body of an email message.
* */
trait EmailMessage {
def headers: Seq[(String, String)]
private def getAddresses(header: String) = headers collect {
case (key, addr) if key.toLowerCase() == header.toLowerCase() => MailingAddress(addr)
}
def from: Seq[MailingAddress] = getAddresses("from")
def sender: MailingAddress = {
if (from.length > 1) {
getAddresses("sender").headOption getOrElse from.head
}
else if (from.length == 0) MailingAddress.empty
else from.head
}
def to: Seq[MailingAddress] = getAddresses("to")
def cc: Seq[MailingAddress] = getAddresses("cc")
def bcc: Seq[MailingAddress] = getAddresses("bcc")
def replyTo: Seq[MailingAddress] = getAddresses("reply-to")
def date: Time =
headers collectFirst {
case (key, d) if key.toLowerCase == "date" => EmailMessage.DateFormat.parse(d)
} getOrElse Time.now
def subject: String =
headers collectFirst {
case (key, subj) if key.toLowerCase == "subject" => subj
} getOrElse ""
def body: Seq[String]
}
object EmailMessage {
val DateFormat: TimeFormat = new TimeFormat("EE, dd MMM yyyy HH:mm:ss ZZ")
}