go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/gae/service/mail/message.go (about) 1 // Copyright 2015 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package mail 16 17 import ( 18 "fmt" 19 net_mail "net/mail" 20 "reflect" 21 22 "google.golang.org/appengine/mail" 23 ) 24 25 // Attachment is a mimic of https://godoc.org/google.golang.org/appengine/mail#Attachment 26 // 27 // It's provided here for convenience, and is compile-time checked to be 28 // identical. 29 type Attachment struct { 30 // Name must be set to a valid file name. 31 Name string 32 Data []byte 33 ContentID string 34 } 35 36 var _ Attachment = (Attachment)(mail.Attachment{}) 37 38 // Message is a mimic of https://godoc.org/google.golang.org/appengine/mail#Message 39 // 40 // It's provided here for convenience, and is init-time checked to be identical 41 // (not statically because []Attachement prevents static casting). 42 type Message struct { 43 Sender string 44 ReplyTo string 45 To, Cc, Bcc []string 46 Subject string 47 Body string 48 HTMLBody string 49 Attachments []Attachment 50 Headers net_mail.Header 51 } 52 53 func init() { 54 mt := reflect.TypeOf(mail.Message{}) 55 ot := reflect.TypeOf(Message{}) 56 if mt.NumField() != ot.NumField() { 57 panic(fmt.Errorf("mismatched number of fields %s v %s", mt, ot)) 58 } 59 60 for i := 0; i < mt.NumField(); i++ { 61 mf := mt.Field(i) 62 of := mt.Field(i) 63 if mf.Name != of.Name { 64 panic(fmt.Errorf("mismatched names %s v %s", mf.Name, of.Name)) 65 } 66 if mf.Name == "Attachments" { 67 if !mf.Type.Elem().ConvertibleTo(of.Type.Elem()) { 68 panic(fmt.Errorf("mismatched element type for Attachments %s v %s", 69 mf.Type, of.Type)) 70 } 71 } else { 72 if mf.Type != of.Type { 73 panic(fmt.Errorf("mismatched type for field %s: %s v %s", mf.Name, mf.Type, of.Type)) 74 } 75 } 76 } 77 } 78 79 func dupStrs(strs []string) []string { 80 if len(strs) > 0 { 81 ret := make([]string, len(strs)) 82 copy(ret, strs) 83 return ret 84 } 85 return nil 86 } 87 88 // ToSDKMessage returns a copy of this Message that's compatible with the native 89 // SDK's Message type. It only needs to be used by implementations (like 90 // "impl/prod") which need an SDK compatible object 91 func (m *Message) ToSDKMessage() *mail.Message { 92 if m == nil { 93 return nil 94 } 95 96 m = m.Copy() 97 98 ret := &mail.Message{ 99 Sender: m.Sender, 100 ReplyTo: m.ReplyTo, 101 Subject: m.Subject, 102 Body: m.Body, 103 HTMLBody: m.HTMLBody, 104 To: m.To, 105 Cc: m.Cc, 106 Bcc: m.Bcc, 107 Headers: m.Headers, 108 } 109 110 ret.Attachments = make([]mail.Attachment, len(m.Attachments)) 111 for i := range m.Attachments { 112 ret.Attachments[i] = (mail.Attachment)(m.Attachments[i]) 113 } 114 return ret 115 } 116 117 // Copy returns a duplicate Message 118 func (m *Message) Copy() *Message { 119 if m == nil { 120 return nil 121 } 122 123 ret := *m 124 125 ret.To = dupStrs(m.To) 126 ret.Cc = dupStrs(m.Cc) 127 ret.Bcc = dupStrs(m.Bcc) 128 129 if len(m.Headers) > 0 { 130 ret.Headers = make(net_mail.Header, len(m.Headers)) 131 for k, vals := range m.Headers { 132 ret.Headers[k] = dupStrs(vals) 133 } 134 } 135 136 if len(m.Attachments) > 0 { 137 ret.Attachments = make([]Attachment, len(m.Attachments)) 138 copy(ret.Attachments, m.Attachments) 139 } 140 141 return &ret 142 }