...
Tawesoft Logo

Source file src/tawesoft.co.uk/go/legacy/email/util.go

Documentation: src/tawesoft.co.uk/go/legacy/email/util.go

     1  package email
     2  
     3  import (
     4      "crypto/rand"
     5      "fmt"
     6      "io"
     7      "mime"
     8      "net/mail"
     9      "strings"
    10      "time"
    11  )
    12  
    13  // msgid generates a unique message ID for a sender
    14  func msgid(from mail.Address) string {
    15      var rnd = make([]byte, 16)
    16      rand.Read(rnd)
    17      var tnow = time.Now().UTC().Format("20060102150405")
    18      var domain = "localhost"
    19      
    20      var atpos = strings.LastIndexByte(from.Address, '@')
    21      if atpos > 0 {
    22          domain = from.Address[atpos:] // includes leading @
    23      }
    24      
    25      return fmt.Sprintf("<%s.%x%s>", tnow, rnd, domain)
    26  }
    27  
    28  // strall returns true iff f(x) is true for each rune in string xs
    29  func strall(
    30      xs string,
    31      f func(c rune) bool,
    32  ) bool {
    33      for _, x := range xs {
    34          // if c > unicode.MaxASCII {
    35          if !f(x) { return false }
    36      }
    37  
    38      return true
    39  }
    40  
    41  // optionalQEncode returns the original string if it is printable ASCII, or a UTF-8 encoded version otherwise.
    42  func optionalQEncode(x string) string {
    43      var onlyPrintableAscii = func(c rune) bool {
    44          return (c >= 0x20) && (c <= 0x7e)
    45      }
    46      
    47      if strall(x, onlyPrintableAscii) {
    48          return x
    49      } else {
    50          return mime.QEncoding.Encode("utf-8", x)
    51      }
    52  }
    53  
    54  // lineBreaker wraps a writer forcing a line break every 76 characters (RFC 2045)
    55  type lineBreaker struct {
    56      column int
    57      writer io.Writer
    58  }
    59  
    60  // Write writes p to the wrapped writer, forcing a line break every 76 characters (RFC 2045) across
    61  // multiple calls to Write
    62  func (lb lineBreaker) Write(p []byte) (n int, err error) {
    63      
    64      const LIMIT = 76 // RFC 2045
    65      var offset int
    66      var written int
    67      lb.column += len(p)
    68      
    69      for offset = 0; lb.column >= 76; lb.column -= LIMIT {
    70          n, err := lb.writer.Write(p[offset:offset + LIMIT])
    71          written += n
    72          if err != nil { return written, err }
    73          
    74          offset += LIMIT
    75          
    76          if offset != len(p) {
    77              n, err := io.WriteString(lb.writer, "\r\n")
    78              written += n
    79              if err != nil { return written, err }
    80          }
    81      }
    82      
    83      if offset != len(p) {
    84          n, err := lb.writer.Write(p[offset:])
    85          written += n
    86          if err != nil { return written, err }
    87      }
    88      
    89      return written, nil
    90  }
    91  

View as plain text