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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
package models
import (
"mime"
"net/mail"
"strings"
"time"
)
type Message struct {
Id string `pg:",pk"`
Filename string
Headers map[string][]string
Body map[string]string
Attachments []Attachment
Lists []string
List string
Date time.Time
//Search types.ValueAppender // tsvector
Comment string
Hidden bool
//ParentId string
//Parent Message -> pg fk?
}
type Header struct {
Name string
Content string
}
type Body struct {
ContentType string
Content string
}
type Attachment struct {
Filename string
Mime string
Content string
}
func (m Message) GetSubject() string {
return m.GetHeaderField("Subject")
}
func (m Message) GetListNameFromSubject() string {
subject := m.GetSubject()
listName := strings.Split(subject, "]")[0]
listName = strings.ReplaceAll(listName, "[", "")
listName = strings.ReplaceAll(listName, "Re:", "")
listName = strings.TrimSpace(listName)
return listName
}
func (m Message) GetAuthorName() string {
addr, err := mail.ParseAddress(m.GetHeaderField("From"))
if err != nil {
return ""
}
return addr.Name
}
func (m Message) GetMessageId() string {
messageId := m.GetHeaderField("Message-Id")
messageId = strings.ReplaceAll(messageId, "<", "")
messageId = strings.ReplaceAll(messageId, ">", "")
messageId = strings.ReplaceAll(messageId, "\"", "")
return messageId
}
func (m Message) GetInReplyTo() string {
inReplyTo := m.GetHeaderField("In-Reply-To")
inReplyTo = strings.ReplaceAll(inReplyTo, "<", "")
inReplyTo = strings.ReplaceAll(inReplyTo, ">", "")
inReplyTo = strings.ReplaceAll(inReplyTo, " ", "")
return inReplyTo
}
func (m Message) GetHeaderField(key string) string {
subject, found := m.Headers[key]
if !found {
return ""
}
header := strings.Join(subject, " ")
if strings.Contains(header, "=?") {
dec := new(mime.WordDecoder)
decodedHeader, err := dec.DecodeHeader(header)
if err != nil {
return ""
}
return decodedHeader
}
return header
}
func (m Message) HasHeaderField(key string) bool {
_, found := m.Headers[key]
return found
}
func (m Message) GetBody() string {
// Get text/plain body
for contentType, content := range m.Body {
if strings.Contains(contentType, "text/plain") {
return content
}
}
// If text/plain is not present, fall back to html
for contentType, content := range m.Body {
if strings.Contains(contentType, "text/html") {
return content
}
}
// If neither text/plain nor text/html is available return nothing
return ""
}
func (m Message) HasAttachments() bool {
for key, _ := range m.Body {
if !(strings.Contains(key, "text/plain") || strings.Contains(key, "text/plain")) {
return true
}
}
return false
}
func (m Message) GetAttachments() []Attachment {
var attachments []Attachment
for key, content := range m.Body {
if !(strings.Contains(key, "text/plain") || strings.Contains(key, "text/plain")) {
attachments = append(attachments, Attachment{
Filename: getAttachmentFileName(key),
Mime: strings.Split(key, ";")[0],
Content: content,
})
}
}
return attachments
}
// utility methods
func getAttachmentFileName(contentTypeHeader string) string {
parts := strings.Split(contentTypeHeader, "name=")
if len(parts) < 2 {
return "unknown"
}
return strings.ReplaceAll(parts[1], "\"", "")
}
|