email

package
v0.0.0-...-a4f4c6b Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 26, 2023 License: GPL-3.0 Imports: 36 Imported by: 0

Documentation

Index

Examples

Constants

View Source
const (
	// ProfilingNew profiles the NewEmail procedure.
	ProfilingNew profilingKey = "NEW"
	// ProfilingAddPart profiles the Email.AddPart method.
	ProfilingAddPart profilingKey = "ADD_PART"
	// ProfilingWrite profiles the Email.Write method.
	ProfilingWrite profilingKey = "WRITE"
	// ProfilingSMTPClientCreation profiles the creation of the SMTP client in TemplateMailer.Send.
	ProfilingSMTPClientCreation profilingKey = "SMTP_CLIENT_CREATION"
	// ProfilingTLSStarted profiles the time it takes for TLS to be started in TemplateMailer.Send.
	ProfilingTLSStarted profilingKey = "TLS_STARTED"
	// ProfilingAuthAdded profiles the time it takes for AUTH to be added in TemplateMailer.Send.
	ProfilingAuthAdded profilingKey = "AUTH_ADDED"
	// ProfilingMailCommand profiles the time it takes to push the MAIL command in TemplateMailer.Send.
	ProfilingMailCommand profilingKey = "MAIL_COMMAND"
	// ProfilingRcptCommand profiles the time it takes to push a single RCPT command in TemplateMailer.Send.
	ProfilingRcptCommand profilingKey = "RCPT_COMMAND"
	// ProfilingDataCommand profiles the time it takes to push the DATA command in TemplateMailer.Send.
	ProfilingDataCommand profilingKey = "DATA_COMMAND"
	// ProfilingDataClose profiles the time it takes to close the DATA command after writing all data to the SMTP server
	// connection in TemplateMailer.Send.
	ProfilingDataClose profilingKey = "DATA_CLOSE"
	// ProfilingWriteTo profiles the Email.WriteTo method.
	ProfilingWriteTo profilingKey = "WRITE_TO"
	// ProfilingClose profiles the Email.Close method.
	ProfilingClose profilingKey = "CLOSE"
)
View Source
const (
	// PixelsToMM is the conversion constant for converting pixels to MM at a 96 DPI.
	PixelsToMM = 0.264583333
	PDFDPI     = 96
)

Variables

This section is empty.

Functions

func ClientCreate

func ClientCreate(config Config) (err error)

func NewParsedTemplate

func NewParsedTemplate(contentType TemplateBufferContentType, context Context) parsedTemplate

Types

type ClientWrapper

type ClientWrapper struct {
	// contains filtered or unexported fields
}

func (*ClientWrapper) Auth

func (c *ClientWrapper) Auth() smtp.Auth

func (*ClientWrapper) Config

func (c *ClientWrapper) Config() Config

func (*ClientWrapper) Send

func (c *ClientWrapper) Send(email *Email) (err error)

func (*ClientWrapper) SendAsync

func (c *ClientWrapper) SendAsync(template *Template) <-chan Response

func (*ClientWrapper) SendSync

func (c *ClientWrapper) SendSync(template *Template) Response

type Config

type Config interface {
	EmailDebug() bool
	EmailHost() string
	EmailPort() int
	EmailAddress() string
	EmailFrom() string
	EmailFromName() string
	EmailPassword() string
	EmailTemplateConfigFor(path TemplatePath) TemplateConfig
}

type Context

type Context interface {
	// Path returns the TemplatePath that this Context is for.
	Path() TemplatePath
	// Template returns an un-executed Template that this Context can be used for.
	Template() *Template
	// Funcs returns the functions that should be bound to the template.Template before parsing the HTML/Text template
	// located in at the TemplatePath.
	Funcs() template.FuncMap
	// Execute executes the Context via Template.Execute.
	Execute() *Template
	// AdditionalParts returns any additional Part to add onto an Email.
	AdditionalParts() ([]Part, error)
}

Context will be implemented by structures that are used to fill out a Template in Template.Execute.

type Email

type Email struct {

	// Profiling is the Profiling instance used to measure the time-of-completion for all actions related to the Email.
	Profiling Profiling
	// FromAddress is the email address of the sender.
	FromAddress string
	// FromName is the name of the sender.
	FromName string
	// Subject is the subject of the Email.
	Subject string
	// Recipients are the email addresses for the recipients of this Email.
	Recipients []string
	// contains filtered or unexported fields
}

Email represents an email MIME multipart file that can be sent using a TemplateMailer.

• First call NewEmail to construct a new Email instance.

• Then set the FromAddress, FromName, Subject, and Recipients fields.

• Add all the parts of the email using AddPart or AddParts. This will encode each Part using Part.Encoder and cache them to the disk.

• Then call Write, to cache the entire MIME multipart email to disk.

• You can then use either Read or ReadBuffered to read the entire MIME multipart email.

• Finally, call Close to close all the Part files and the Email file as well as to remove these files from the disk.

Note: the last three steps should all be performed by the TemplateMailer.Send method anyway.

func NewEmail

func NewEmail() (email *Email, err error)

NewEmail creates a new Email instance and creates a temporary file to hold the finished multipart request.

Example
inTest = true
defer func() {
	inTest = false
}()
var (
	email *Email
	err   error
)

if email, err = NewEmail(); err != nil {
	fmt.Println(err)
}
email.Recipients = []string{"dest@dest.com"}
email.Subject = "Hello world!"
email.FromName = "Test"
email.FromAddress = "test@test.com"
defer email.Close()

if err = agem.MergeErrors(
	email.AddPart(Part{Buffer: bytes.NewReader([]byte("Hello world!"))}),
	email.AddPart(Part{Buffer: bytes.NewReader([]byte("<h1>Hello world!</h1>"))}),
	email.AddPart(Part{
		Buffer:      bytes.NewReader([]byte("a,b,c\n1,2,3")),
		ContentType: "text/csv; charset=utf-8",
		Attachment:  true,
		Filename:    "test.csv",
	}),
); err != nil {
	fmt.Println(err)
}

if err = email.Write(); err != nil {
	fmt.Println(err)
}

fmt.Printf("Final email size: %d\n", email.Size())
fmt.Println(email.Profiling.String())

// Convert DOS line-endings to UNIX so that we can check the output.
fmt.Println(strings.ReplaceAll(email.Read().String(), "\r\n", "\n"))
Output:

Final email size: 463
Total duration: X
1: ADD_PART was called 3 time(s) with an overall time of X (XX.XX%)
2: NEW was called 1 time(s) with an overall time of X (XX.XX%)
3: WRITE was called 1 time(s) with an overall time of X (XX.XX%)
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary=BOUNDARY
From: Test <test@test.com>
To: dest@dest.com
Subject: Hello world!
--BOUNDARY
Content-Type: text/plain; charset=utf-8

Hello world!
--BOUNDARY
Content-Type: text/html; charset=utf-8

<h1>Hello world!</h1>
--BOUNDARY
Content-Disposition: attachment; filename=test.csv
Content-Transfer-Encoding: base64
Content-Type: text/csv; charset=utf-8

YSxiLGMKMSwyLDM=
--BOUNDARY--

func (*Email) AddPart

func (e *Email) AddPart(part Part) (err error)

AddPart will add a Part with a Part.Buffer to the Email. This will encode the Part to its required encoding and cache the Part intermittently to the disk.

func (*Email) AddParts

func (e *Email) AddParts(parts ...Part) (err error)

AddParts will call AddPart for all provided Part.

func (*Email) Close

func (e *Email) Close() (err error)

Close will close and remove all the temp files created by the Email.

func (*Email) From

func (e *Email) From() string

From returns the FromName and FromAddress in the format that the email header requires.

func (*Email) Read

func (e *Email) Read() *bytes.Buffer

Read will return a bytes.Buffer containing all of the final MIME multipart email request.

func (*Email) ReadBuffered

func (e *Email) ReadBuffered() *bufio.Reader

ReadBuffered will return a bufio.Reader for the final MIME multipart email request.

func (*Email) Size

func (e *Email) Size() int64

Size is the size of the final Email in bytes. This is equal to the size of the temporary file used to store the email within.

func (*Email) Write

func (e *Email) Write() (err error)

Write will construct the final Email from all the cached parts. This final multipart request will also be cached to disk in a temporary file.

func (*Email) WriteTo

func (e *Email) WriteTo(w io.Writer) (n int64, err error)

WriteTo will write the Email to the given io.Writer in chunks, as to not load all the Email into memory. Write still needs to be called before this.

type FinishedContext

type FinishedContext struct {
	BatchSize       int
	DiscoveryTweets int
	Started         time.Time
	Finished        time.Time
	Result          *models.ScoutResult
}

func (*FinishedContext) AdditionalParts

func (f *FinishedContext) AdditionalParts() ([]Part, error)

func (*FinishedContext) Execute

func (f *FinishedContext) Execute() *Template

func (*FinishedContext) Funcs

func (f *FinishedContext) Funcs() template.FuncMap

func (*FinishedContext) Path

func (f *FinishedContext) Path() TemplatePath

func (*FinishedContext) Template

func (f *FinishedContext) Template() *Template

type MeasureContext

type MeasureContext struct {
	Start                  time.Time
	End                    time.Time
	TrendingDevs           []*models.TrendingDev
	TopSteamApps           []*models.SteamApp
	DevelopersBeingDeleted []*models.TrendingDev
	WatchedDevelopers      []*models.TrendingDev
	WatchedSteamApps       []*models.SteamApp
	Config                 Config
}

MeasureContext is a Context that contains the data required to fill out the Measure HTML template.

func (*MeasureContext) AdditionalParts

func (m *MeasureContext) AdditionalParts() ([]Part, error)

func (*MeasureContext) DeletedDevelopersWithGames

func (m *MeasureContext) DeletedDevelopersWithGames() []*models.TrendingDev

DeletedDevelopersWithGames filters out all models.TrendingDev in DevelopersBeingDeleted with no models.Game related to them.

func (*MeasureContext) Execute

func (m *MeasureContext) Execute() *Template

func (*MeasureContext) Funcs

func (m *MeasureContext) Funcs() template.FuncMap

func (*MeasureContext) HasWatched

func (m *MeasureContext) HasWatched() bool

HasWatched returns true when there are WatchedDevelopers or WatchedSteamApps.

func (*MeasureContext) Path

func (m *MeasureContext) Path() TemplatePath

func (*MeasureContext) Template

func (m *MeasureContext) Template() *Template

func (*MeasureContext) WatchedDevelopersWithGames

func (m *MeasureContext) WatchedDevelopersWithGames() []*models.TrendingDev

WatchedDevelopersWithGames filters out all models.TrendingDev in WatchedDevelopers that don't contain a models.Developer.

func (*MeasureContext) WatchedGames

func (m *MeasureContext) WatchedGames() []*models.Game

WatchedGames filters out all models.TrendingDev in WatchedDevelopers that contain a models.Developer.

func (*MeasureContext) WatchedGamesWithDummyDevs

func (m *MeasureContext) WatchedGamesWithDummyDevs() []*models.TrendingDev

type Part

type Part struct {
	Buffer *bytes.Reader

	// ContentType can be provided, but if it is the empty string then it will be found from the first 512 bytes of the
	// Buffer using http.DetectContentType.
	ContentType string
	// Attachment should be set to true if the Part should be added as an attachment. If this is set then Filename
	// should also be set.
	Attachment bool
	// Filename is the filename of the attachment.
	Filename string
	// DropIfBig will drop the attachment from the email if its base64 encoded version larger than 25MB.
	DropIfBig bool
	// contains filtered or unexported fields
}

Part stores the information for a single part of an Email. When passing a Part to Email.AddPart Buffer should be set so that the Part can be intermittently cached to a file.

func (*Part) ContentTypeSlug

func (p *Part) ContentTypeSlug() string

ContentTypeSlug returns the slugified version of the ContentType that can be used within the names of the temporary file created for the Part.

func (*Part) Encoder

func (p *Part) Encoder() (io.WriteCloser, error)

Encoder returns an io.WriteCloser for the Part's buffer. If the Part is an Attachment, then the encoder returned will be a base64 encoder, anything else will be encoded as plain-text.

func (*Part) Headers

func (p *Part) Headers() textproto.MIMEHeader

Headers returns the textproto.MIMEHeader for the Part by using the ContentType.

type Profiling

type Profiling map[profilingKey][]time.Duration

Profiling stores all the profiling that has been done for an Email.

func (*Profiling) String

func (prof *Profiling) String() string

String returns the all the profiles that have been created within Profiling in the time-taken order.

func (*Profiling) Total

func (prof *Profiling) Total() time.Duration

Total returns the total time we spent profiling an Email.

type Response

type Response struct {
	Email *Email
	Error error
}

type Template

type Template struct {
	// Path is the TemplatePath where the Template was loaded from.
	Path TemplatePath
	// Template is the parsed template.Template or textTemplate.Template, loaded from the Path, which is also loaded up
	// with the functions returned by Context.Funcs method for the Context for this Template.
	Template parsedTemplate
	// Config is the TemplateConfig for this template.
	Config TemplateConfig
	// Buffer is a bytes.Reader that contains the parsed output for the results produced by Template.Execute and
	// Template.PDF. This is overwritten each time.
	Buffer bytes.Reader
	// Error is the error returned by any of the chained methods.
	Error error
	// ContentType is the current TemplateBufferContentType of the Buffer.
	ContentType TemplateBufferContentType
	// Context is the Context that this Template will/has used to generate HTML or Text from the TemplatePath.
	Context Context
}

Template is a chainable structure that represents an instantiated HTML template that is read from the given Path. It is worth noting that the chainable methods return copies of the original Template.

func (*Template) Email

func (t *Template) Email() (email *Email, err error)

Email returns the filled Email instance that can be sent using the email Client.

• If the given Template has an error set in Template.Error then this error will be wrapped and returned.

• If the given Template has a ContentType of Text, then the sent email will have a plain-text body.

• If the given Template has a ContentType of HTML, then the sent email will have an HTML body, a plain-text body obtained from html2text.FromString, and the HTML will be added as an attachment.

• If the given Template has a ContentType of PDF, then the sent email will have an HTML body obtained by executing a brand-new template with the Template.Context, a plain-text body obtained from html2text.FromString, and the PDF will be added as an attachment.

• If the given Template does not have a ContentType that is either Text, HTML or PDF, then an error will be returned.

Any additional Part returned by Context.AdditionalParts will also be added.

func (*Template) Execute

func (t *Template) Execute() (output *Template)

Execute will call Template.Template.Execute with the given Template.Context. Template.Error is set if:

• The Template already contains an error.

• The Template.ContentType is not NotExecuted.

• The resulting value of Context.Path does not match the Template.Path.

• An error occurs whilst calling the Execute method on Template.Template.

If Template.Execute can run without setting the Template.Error then Template.ContentType is set to HTML or Text depending on the TemplateBufferContentType returned by Template.Template.ExecutedContentType.

func (*Template) PDF

func (t *Template) PDF() (output *Template)

PDF will convert a Template with the ContentType HTML to a PDF. Template.Error is set if:

• The Template already contains an error.

• The Template.ContentType is not HTML.

• An error occurred in any of the functions used to generate the PDF.

If Template.PDF can run without setting the Template.Error then Template.ContentType is set to PDF. PDF will calculate the size of the generated PDF by opening the HTML in a headless playwright browser, then fetch the height and width (in pixels) of the first element to use the .container class on the page. These values are then converted to MM by using the PixelsToMM conversion constant, which assumes that the PDF DPI is 96.

func (*Template) SendAsync

func (t *Template) SendAsync() <-chan Response

SendAsync the Template using the default TemplateMailer (Client) with ClientWrapper.SendAsync.

func (*Template) SendAsyncAndConsume

func (t *Template) SendAsyncAndConsume(consumer func(resp Response))

SendAsyncAndConsume will send the Template using the default TemplateMailer (Client) with Template.SendAsync and will consume the response using the given function. If a Response is never returned from Template.SendAsync, then the consumer function will never be run.

func (*Template) SendSync

func (t *Template) SendSync() Response

SendSync the Template using the default TemplateMailer (Client) with ClientWrapper.SendSync.

func (*Template) WriteFile

func (t *Template) WriteFile(filename string) (err error)

WriteFile will write the Buffer to a file of the given filename.

type TemplateBufferContentType

type TemplateBufferContentType int

TemplateBufferContentType is an enum representing the possible content-types of the Template.Buffer.

const (
	// NotExecuted is the TemplateBufferContentType that is initially given to a Template constructed by
	// TemplatePath.Template.
	NotExecuted TemplateBufferContentType = iota
	// Text is set after the Template.Execute method is called successfully on a Text Template. Text templates cannot be
	// converted to HTML or PDF.
	Text
	// HTML is set after the Template.Execute method is called successfully on an HTML Template.
	HTML
	// PDF is set after the Template.PDF method is called successfully.
	PDF
)

func (TemplateBufferContentType) String

func (ct TemplateBufferContentType) String() string

String returns the formal name of the TemplateBufferContentType.

type TemplateConfig

type TemplateConfig interface {
	TemplateMaxImageWidth() int
	TemplateMaxImageHeight() int
	TemplateDebugTo() []string
	TemplateTo() []string
	TemplateSendRetries() int
	TemplateSendBackoff() (time.Duration, error)
	TemplateSubject() string
	TemplateAttachmentName() string
	TemplateHTML2TextOptions() html2text.Options
	TemplatePlainOnly() bool
	TemplateSendDay() time.Weekday
}

type TemplateMailer

type TemplateMailer interface {
	Send(email *Email) (err error)
	SendAsync(template *Template) <-chan Response
	SendSync(template *Template) Response
	Auth() smtp.Auth
	Config() Config
}
var Client TemplateMailer

type TemplatePath

type TemplatePath string

TemplatePath represents the path of an HTML template in the repo. Each template that is going to be converted to PDF, must contain an element that implements a .container class. This is used to calculate the width of the final generated PDF.

const (
	Measure  TemplatePath = templateDir + "measure.html"
	Started  TemplatePath = templateDir + "started.txt"
	Error    TemplatePath = templateDir + "error.txt"
	Finished TemplatePath = templateDir + "finished.txt"
)

func TemplatePathFromName

func TemplatePathFromName(name string) TemplatePath

TemplatePathFromName returns the TemplatePath of the given name.

func (TemplatePath) Name

func (tt TemplatePath) Name() string

Name returns the name of the TemplatePath that is synonymous to the name of the enum constant.

func (TemplatePath) Path

func (tt TemplatePath) Path() string

Path returns the string value of the TemplatePath.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL