Git Product home page Git Product logo

go-simple-mail's Introduction

Hi there I'm Santiago 👋

stgo.do hi@stgo.do

  • 🔭 I’m currently working on Ofimatic and AJ IT Electronics Solutions
  • 🌱 I’m currently learning about a lot of things and how to integrate them
  • 👯 I’m looking to collaborate on software integration
  • 💬 Ask me about anything
  • ⚡ Fun fact #1: My life follow The KISS principle
  • ⚡ Fun fact #2: I'm not a developer. I like to solve problems using code
  • ⚡ Fun fact #3: Solve the problem. Refactor later... If need it
  • 🚧 Current Project: Dixer

go-simple-mail's People

Contributors

alex1989hu avatar arturwwl avatar atifceylan avatar codestation avatar davrux avatar dmke avatar falconandy avatar gerardrodes avatar herz3h avatar jlinnosa avatar joegrasse avatar kennethklee avatar meain avatar mukul-brevo avatar nikoksr avatar norguhtar avatar simaotwx avatar simonerota avatar smirnoff2019 avatar utkarshmani1997 avatar vjeantet avatar xhit avatar yene avatar yusufozturk avatar zyxkad avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-simple-mail's Issues

Use mail.Address instead of plain strings

With simple plain strings we are unable to set the name, only the address of the recipient(s).
Use mail.Address.String() for headers, where full format works, and use mail.Address.Address for smtp's mail and rcpt methods to make it work with the smtp protocol.

Cant send mail

Hello
I cant send email, this is error code that i am getting:
Mail Error on Auth: 535 5.7.8 Error: authentication failed: UGFzc3dvcmQ6

Code:


import (
	"fmt"

	mail "github.com/xhit/go-simple-mail/v2"
)

func main() {
	//Create the email message
	server := mail.NewSMTPClient()
	server.Host = "smtp.poczta.onet.pl"
	server.Port = 465
	server.Username = "[email protected]"
	server.Password = "pass"

	server.Authentication = mail.AuthLogin
	server.Encryption = mail.EncryptionSSLTLS
	// server.TLSConfig = &tls.Config{InsecureSkipVerify: true}

	smtpClient, err := server.Connect()

	if err != nil {
		fmt.Println("error ")
		fmt.Println(err)
		return
	}

	fmt.Println("connected")

	email := mail.NewMSG()

	email.SetFrom("From aa <[email protected]>").
		AddTo("").
		SetSubject("New Go Email")

	//Get from each mail
	email.GetFrom()
	email.SetBody(mail.TextPlain, "Hello Test")

	//Send with high priority
	email.SetPriority(mail.PriorityHigh)

	// always check error after send
	if email.Error != nil {
		fmt.Println(email.Error)
		return
	}

	//Pass the client to the email message to send it
	fmt.Println(email.Send(smtpClient))
}

Logs:

error 
Mail Error on Auth: 535 5.7.8 Error: authentication failed: UGFzc3dvcmQ6

Implement reconnect or reconnect helper from #23

I ended up spending several hours trying to make a type that would wrap the SMTPClient type and do the NOOP sending to implement the suggestion in this comment before I realized there was no easy way to track the last time an email was sent for the timer, and you cannot do that by wrapping a SMTPClient because the email type is what sends the email in Email.Send, by calling an an unexported internal function. This means that I need to create a special EmailProvider which returns a new type embedding Email so that I can wrap Email.Send and Email.SendEnvelopeFrom to track the SMTPClient with a mutex and reset the loop. Also SMTPClient has an exported Client field, which returns the unexported internal smtpClient type, which is unfortunately useless. So I cannot have the SMTPServer reconnect the internal smtpClient, and I must use EmailProvider to do that. It's a bit convoluted and not nearly as easy as the solution in #23 would suggest.

It would be nice if there was a way to do this in the library, or if you could provide a type like my EmailProvider that wraps the client and server objects to re-create it when necessary.

V3 help

Hello, I hope you are happy using this package :)

Currently I'm too busy, and I know this package needs some features proposed in this discussion #53

I left a branch here for V3 https://github.com/xhit/go-simple-mail/tree/v3, feel free to add some features, breaking changes, enhancement, etc... that you think is needed, I will check all PRs.

The PR destination should be v3 branch.

Also, If you want to be a maintainer, please respond this issue :)

Suggestion: make contentType enum public

First of all, thank you for this great library.

If you can make mail.contentType enum public, we can hold plain text or html formats in enum instead of integer values.

Right now, we do:

// Check Content Type
if message.ContentType == 1 {
  // Set Body HTML String
  email.SetBody(mail.TextHTML, message.Body)
} else {
  // Set Body Plain String
  email.SetBody(mail.TextPlain, message.Body)
}

What I want to do, is setting message.ContentType as mail.ContentType, so I can use directly:

email.SetBody(message.ContentType, message.Body)

If you accept this suggestion, I can prepare a PR.

Thanks.

Client does not reconnect on network failure, even with KeepAlive

I had a smtp connexion OK (with keepalive), when suddently the remote server closed it.
Since this event no mail were sent, event if the remote server is back online.

Here is the log i have each time i send a mail since the event.

write tcp 127.0.0.1:60591->127.0.0.1:25: wsasend: An existing connection was forcibly closed by the remote host.  

The only way to get my mails sent again, was by killing/starting my app.

You can easily reproduce this case with mailHog, by activating "JIM" with -invite-jim -jim-disconnect "1"

OAuth2.0

Hello there,

is there any interest or maybe already any ongoing development (though i did not see anything in the branches) regarding a generic OAuth2.0 implementation?
Microsoft seems to force everyone from BasicAuthentication to OAuth2.0

I am a big fan of this package due to its simplicity and i was wondering if anyone else stumbled across this?

I noticed you are aware that OAuth2 is not working in this issue
Are you interested in adding OAuth2 as this will be the next Generation of Authentications?
I probably could help implementing it, if you are interested.

Best regards,
LarsTi

SMTP Connection timed out

Hello, I want to use the example to test program but I had a problem ..
I use the right parameter and good password and error is coming ^^

Mail Error: SMTP Connection timed out

My fault or any problem with localhost, tls or another one ?

Thanks a lot

image

image

Not possible to send only to cc or bcc

The package return error when send only to Cc or Bcc. Requires the To header.

Sending a mail from gmail or outlook with only specified Cc or Bcc works.

MISSING_MIMEOLE Message has X-MSMail-Priority, but no X-MimeOLE

I got this message in mailtrap.io "Spam check":
MISSING_MIMEOLE Message has X-MSMail-Priority, but no X-MimeOLE

image

Is all good with this header?

SpamAssassin Rule: MISSING_MIMEOLE

Standard description: Message has X-MSMail-Priority, but no X-MimeOLE

Explanation

The message is pretending to be generated by a Microsoft email program which uses the extension header X-MSMail-Priority, but is missing the extension header X-MimeOLE which is characteristic of Microsoft email.

This suggests that the sender is using badly-written mailout software, rather than a genuine Microsoft email program.

error info inappropriate when auth password need update

the email service which is used by me, has the Passwords need to be updated regularly mechanism.
so the account will be locked can not login when It's been a long time since last login.
in this case, the library give error info like belong

Mail Error: SMTP Connection timed out
Mail Error: No SMTP Client Provided

In this case, can you give a password related error message: The account password is correct, but the password needs to be updated, so you cannot log in immediately. You need to change the password and log in again.

Get encrypted function

Please provide a function that can get the encryption, For example: SMTP = > encryption TLS

const (
	// EncryptionNone uses no encryption when sending email
	EncryptionNone encryption = iota
	// EncryptionSSL sets encryption type to SSL when sending email
	EncryptionSSL
	// EncryptionTLS sets encryption type to TLS when sending email
	EncryptionTLS
)

Context

Can you make connecting to the server and sending messages using context?

Mail not reciving to Yahoo Accounts

Hi,
Mails not receiving to yahoo accounts. Getting the error message 5.6.7(destination does not support SMTPUTF8 required for message delivery).
Please give a soulution

Exporting authType type

Hello @xhit

First, thanks for the package !

Would it make sense to make the type type authType public like what you have done for Encryption?

So in a method which creates the SMTP client could take the authType as string then cast it to authType.

Cheers.

Why is the NewClient function used to create a server?

The library is very good. I'm going to use it. But there are several questions. Why is the NewClient function used to create a server?
server := mail.NewSMTPClient()
Don't you think this is illogical? Or am I missing something?

Cannot connect SMTP of outlook

Hi,

I found problem to connect with smtp outlook this always SMTP Connection timed out. But in gmail it work fine.

sample code and error :
Screen Shot 2564-08-27 at 16 52 19

Screen Shot 2564-08-27 at 16 52 32

smtp setting for outlook :
Uploading Screen Shot 2564-08-27 at 16.55.24.png…

No mail send

Hi there,

Wireguard ui is using this program for sending mail...
I found that mail server settings are stored in /etc/envirionment but it's not working

hostname=smtp.gmail.com
port=587
username=[email protected]
password=vlqsolltfknmwfcd #generated app passwd
authType=PLAIN
encryption=TLS
noTLSCeck=no
fromName="This Email"
from="[email protected]"

I have installed ssmtp and this can send mail..

Why is it not possible to use proxy?

I saw question and comment about proxy in closed issue.

However it's not a network issue.

With "net/smtp" and "golang.org/x/net/proxy" we can easily create smtpClient through proxy:

Dial, err := proxy.SOCKS5("tcp", "some-proxy-address", nil, proxy.Direct)
if err != nil {
	return nil, errors.Wrap(err, "Create SOCKS5")
}

dialer, err = Dial.Dial("tcp", "host-addr")
if err != nil {
	return nil, errors.Wrap(err, "Dial")
}

conf := &tls.Config{ServerName: "host-addr-without-port"}
tlsdialer := tls.Client(dialer, conf)

client, err := smtp.NewClient(tlsdialer, "host-addr")
if err != nil {
	panic(err)
}

auth := smtp.PlainAuth("", user, pass, "host-addr")
if err = client.Auth(auth); err != nil {
	panic(err)
}

And would be awesome if smth like this would be possible in this package. Cuz it's quite convient for sending mail.
Or if it's too much trouble, then why was smtpClient made not exportable in the first place. It has couple slight differences with net's smtp.Client type: there's a instead of auth and Text made exportable.
If instead of creating separate type net's smtp.Client was used then we would have proxy as in code above.
Even if there's a different type, then methods to change connections would work too.

Or add couple params to SMTPServer type for proxy and on connect if there are filled in use them for connection.
So many ways to do it. Wander why it wasn't done in the first place. (

StarTTLS problems

Hello there.
Geting

Must issue a STARTTLS command first.

Error when trying to use smtp.gmail.com as host.
Is it possible to use use gmail host? I was trying other go-mail package with Google App password and everything worked
Here is the code:

	server := mail.NewSMTPClient()
	server.Port = 587
	server.Username = "<my gmail>"
	server.Password = "<App password for this gmail>"
	server.Host = "smtp.gmail.com"

	client, err := server.Connect()
	if err != nil {
		return err
	}
	
	server.Encryption = mail.EncryptionSTARTTLS
	server.TLSConfig = &tls.Config{InsecureSkipVerify: true}
	//Tried without those options and got the same error 

	email := mail.NewMSG()
	email.SetFrom("<my gmail>")
	email.AddTo("<my other gmail>")
	email.SetBody(mail.TextPlain, "this is a test")
	if email.Error != nil{
		log.Fatal(email.Error)
	}

	err = email.Send(client)
	if err != nil {
		log.Println(err)
	} else {
		log.Println("Email Sent")
	}
	return nil
}

Am I missing something?
Thanks in advance

Unify attachment handling API

Currently we have the following function signatures for adding attachments to an Email struct:

func (email *Email) AddAttachment(file string, name ...string) *Email
func (email *Email) AddAttachmentBase64(b64File, name string) *Email
func (email *Email) AddAttachmentData(data []byte, filename, mimeType string) *Email
func (email *Email) AddInline(file string, name ...string) *Email
func (email *Email) AddInlineBase64(b64File, name, mimeType string) *Email
func (email *Email) AddInlineData(data []byte, filename, mimeType string) *Email

For some reason AddAttachment and AddInline are variadic but only accept one name:

        if len(name) > 1 {
                email.Error = errors.New("Mail Error: Attach can only have a file and an optional name")
                return email
        }

Other functions take name as parameter and possibly also mimeType.

I propose we modify all these functions to accept name and mimeType. So the API would become:

func (email *Email) AddAttachment(file, name, mimeType string) *Email
func (email *Email) AddAttachmentBase64(b64Data, name, mimeType string) *Email
func (email *Email) AddAttachmentData(data []byte, name, mimeType string) *Email
func (email *Email) AddInline(file, name, mimeType string) *Email
func (email *Email) AddInlineBase64(b64Data, name, mimeType string) *Email
func (email *Email) AddInlineData(data []byte, name, mimeType string) *Email

edit. I changed argument name b64File -> b64Data so it is consistent with file and data arguments.

Mixture of line endings

The repository contains files both CRLF and LF file endings.

Examples, not a complete list:

  • CRLF: .gitattributes, smtp_test.go, LICENSE
  • LF: go.mod, smtp.go

[Proposal] func (*Email) SetBodyData(contentType contentType, body []byte) *Email

Hi,
I would like to propose a small feature to the current API by providing

func (*Email) SetBodyData(contentType contentType, body []byte) *Email

to initialize body part buffer with byte slice instead of a string.
It would help reducing the memory allocation when converting a []byte -> string -> []byte buffer.
Thanks again.

Discarding duplicate email address and setting error

Hi
Thanks for creating this package, great work 👍

I wanted to know if is there any specific reason why you are not adding a duplicate email address in recipients and setting error on email also?

email.recipients, err = addAddress(email.recipients, address.Address)
	if err != nil {
		email.Error = errors.New("Mail Error: " + err.Error() + "; Header: [" + header + "] Address: [" + addresses[i] + "]")
		return email

Improvement: Reuse Connection (or unclear documentation)

Hey, first things first: nice package, thank you for that. But it seems that it is not really possible to keep one connection open?

I want to run this in the background and from time to time send a mail. As far as I understood the documentation (or sadly/more precisely the code 😬) right, it is not intended to reuse a client? Instead I should create a new client for each message (or hope that the connection is still open/use client.noop and maybe re-create the client)? This seems a bit wasteful to open a new connection for every message.

Maybe this could be an improvement for v3? 😁

Limit send

Does the sending limit depend on the host used?

Error starting tcp server

Before that I used Linux, when I switched to Windows, I started to get an error when starting the program:
Mail Error on dialing with encryption type STARTTLS: dial tcp 127.0.0.1:587: connectex: No connection could be made because the target machine actively refused it.

Export priority type

Hi @xhit,

thanks for your work on this! Just a quick question regarding the priority type. Is there any reason why it's not exported? It being an unexported type makes it kinda annoying to translate priorities between this and other packages.

If there's a specific reason, please let me know. If not, I got a PR basically ready!

Cheers

Add a way to attach calendar invites

Calendar invite attachments can be considered alternative views.

Perhaps we can add a email.AddInvite(s string) that appends the invite to email.parts with content type text/calendar; method=REQUEST?
Or maybe add a content type of text/calendar so we can use email.AddAlternative?

Thoughts?

How to run tests?

The example_test.go wants to connect to localhost:25. I'm not certain, I want to install a mail server on my machine. I definitively won't install a Go environment on my mail server.

$ go test ./...
--- FAIL: TestSendMail (0.00s)
    example_test.go:50: Expected nil, got Mail Error on dailing with encryption type None: dial tcp [::1]:25: connect: connection refused connecting to client
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
        panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x63d18c]

goroutine 19 [running]:
testing.tRunner.func1.1(0x6749a0, 0x8a9cf0)
        /home/dm/.local/go/src/testing/testing.go:941 +0x3d0
testing.tRunner.func1(0xc00014e240)
        /home/dm/.local/go/src/testing/testing.go:944 +0x3f9
panic(0x6749a0, 0x8a9cf0)
        /home/dm/.local/go/src/runtime/panic.go:967 +0x15d
github.com/xhit/go-simple-mail/v2.(*SMTPClient).Noop(...)
        /home/dm/code/go-simple-mail/email.go:830
github.com/xhit/go-simple-mail/v2.TestSendMail(0xc00014e240)
        /home/dm/code/go-simple-mail/example_test.go:55 +0x1bc
testing.tRunner(0xc00014e240, 0x6cc578)
        /home/dm/.local/go/src/testing/testing.go:992 +0xdc
created by testing.(*T).Run
        /home/dm/.local/go/src/testing/testing.go:1043 +0x357
FAIL    github.com/xhit/go-simple-mail/v2       0.005s
FAIL

I'd be OK with running the tests in a confined environment, like a Docker container. Do you have something prepared for this?

In the same vein: Are there plans to automate test runs on commit, with say Github Actions?

No SMTP Client Provided if authentication fails

If ConnectTimeout is 0 (means no timeout) and credentials are not correct (incorrect username or password or both) then the returned SMTPClient is nil and error too.

The error Mail Error: No SMTP Client Provided is displayed instead and authentication error.

Race on timeout

When SendTimeout is triggered, send() will result in a race since client is used in 2 different goroutines at the same time. This is happening because textproto.Conn isn't thread-safe, and we are calling .quit() and .Close() at the same time.

I am including test code here. Save it as a test file inside the same package and run it with go test -race -test.run=TestSendRace.

package mail

import (
	"fmt"
	"log"
	"net"
	"testing"
	"time"
)

func TestSendRace(t *testing.T) {
	port := 56666
	timeout := 1 * time.Second
	startService(port, []string{
		`220 test connected`,
		`250 after helo`,
		`250 after mail from`,
		`250 after rcpt to`,
		`354 after data`,
	})

	server := NewSMTPClient()
	server.ConnectTimeout = timeout
	server.SendTimeout = timeout
	server.KeepAlive = false
	server.Host = `localhost`
	server.Port = port

	smtpClient, err := server.Connect()
	if err != nil {
		log.Fatalf("couldn't connect: %s", err.Error())
	}
	defer smtpClient.Close()

	err = SendMessage(`foo@bar`, []string{`rcpt@bar`}, "body", smtpClient)
	if err != nil {
		log.Fatalf("couldn't send: %s", err.Error())
	}
}

func startService(port int, responses []string) {
	log.Printf("starting service at %d...\n", port)
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
	if err != nil {
		log.Fatalf("couldn't listen to port %d: %s", port, err)
	}

	go func() {
		for {
			conn, err := listener.Accept()
			if err != nil {
				log.Fatalf("couldn't listen accept the request in port %d", port)
			}
			go respond(conn, responses)
		}
	}()
}

func respond(conn net.Conn, responses []string) {
	buf := make([]byte, 1024)
	for i, resp := range responses {
		conn.Write([]byte(resp + "\n"))
		n, err := conn.Read(buf)
		if err != nil {
			log.Println("couldn't read data")
			return
		}
		readStr := string(buf[:n])
		log.Printf("READ:%s", string(readStr))

		if i == len(responses)-1 {
			break
		}
	}
	time.Sleep(5 * time.Second)
	conn.Write([]byte(`221 after quit` + "\n"))
	conn.Close()
}

Mail Error: SMTP Connection timed out

Hey,
I'm trying to send emails from an outlook address but I get the error Mail Error: SMTP Connection timed out after the time out.
Here's the informations provided by Microsoft (found two sources, one from Microsoft's support, the other from email's settings):

SMTP hostname: smtp-mail.outlook.com (or smtp.office365.com, tried both)
Port: 587
Encryption: STARTTLS

Here's my code:

server := mail.NewSMTPClient()
server.Host = os.Getenv("SMTP_HOST")
server.Port = 587
server.Username = os.Getenv("EMAIL")
server.Password = os.Getenv("EMAIL_PASSWORD")
server.Encryption = mail.EncryptionSTARTTLS

server.KeepAlive = false
smtpClient, err := server.Connect()
if err != nil {
   return err
}
body := "<html><body><p>Hey,</p><p><a href='" +
		os.Getenv("SERVER_ADDRESS") +
		"/verifyEmail?code=" +
		code +
		"'>Click here to confirm your email</a></p><p>Cordially,</p></body></html>"
email := mail.NewMSG()
email.SetFrom("Test Email <" + os.Getenv("EMAIL") + ">").
   AddTo("<a real address>").
   SetSubject("E-mail verification")
   email.SetBody(mail.TextHTML, body)

if email.Error != nil {
   return email.Error
}

err = email.Send(smtpClient)
if err != nil {
   return err
}

Thanks in advance for your help!

Can't go get

$ go get -u github.com/xhit/go-simple-mail/v2
cannot find package "github.com/xhit/go-simple-mail/v2" in any of:
        ...\github.com\xhit\go-simple-mail\v2 (from $GOROOT)
        ...\github.com\xhit\go-simple-mail\v2 (from $GOPATH)

I guess this is related to go modules?

Add methods to inspect body

Hey,
Firstly I would like to say that this is an awesome package.

I would to request a set of methods to access the msg body for both html and alternative/text. Would this be possible?

Support for gmail?

Many clients simply error out on gmail due to "Less Secure Access"; Does this library have a fix for that?

text/calendar example

After a bit of research, I found out that this project is capable of using a calendar in the body (#50). Can someone give me an example of how to create the ics data that is acceptable to be used? I don't see any example on the PR that has been merged.

func (email *Email) Send(client *SMTPClient) not goroutine safe

i do some test with keepalive,but got some wrong (smtp server with mailhog )

2020/11/22 01:42:01 [SMTP 172.21.0.1:40294] [PROTO: RCPT] In RCPT state
2020/11/22 01:42:01 [SMTP 172.21.0.1:40294] [PROTO: RCPT] Got unknown command for RCPT state: '&{MAIL FROM:<[email protected]> MAIL FROM:<[email protected]>}'
2020/11/22 01:42:01 [SMTP 172.21.0.1:40294] Sent 26 bytes: '500 Unrecognised command\r\n'
2020/11/22 01:42:01 [SMTP 172.21.0.1:40294] Received 31 bytes: 'RCPT TO:<[email protected]>\r\nRSET\r\n'

some links https://github.com/rongfengliang/golang-email-learning/blob/master/main.go#L15

Thread safety

Hi! Is it thread save to invoke server.Connect on multiple "threads", or I need to create new server each time?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.