Wednesday, January 2, 2019

Sending Email

Simple Mail Transfer Protocol (SMTP) is the protocol used for sending email. SMTP dictates how email messages should be formatted, encrypted, and relayed between mail servers, and all the other details that your computer handles after you click Send. Python’s smtplib module simplifies these actions so that a programmer can easily work with SMTP without knowing much technical details. In Python we need to call functions to perform each major step of SMTP.

When working with e-mail, we create a message using an e-mail application. As part of the e-mail application setup, we also define account information. When we click send:

1. The e-mail application wraps up our message, with the header first, in an envelope that includes both our sender and the recipient’s information.

2. The e-mail application uses the account information to contact the SMTP server and send the message for us.

3. The SMTP server reads only the information found in the message envelope and redirects our e-mail to the recipient.

4. The recipient e-mail application logs on to the local server, picks up the e-mail, and then displays only the message part for the user.

When the SMTP server processes the envelope for an e-mail, it must look at the specifics of the address which contains:

1. Host: A host address is the address used by the card that is physically connected to the Internet, and it handles all the traffic that the Internet consumes or provides for this particular machine. A PC can use Internet resources in a lot of ways, but the host address for all these uses is the same.

2. Port: The port specifies which specific part of the system should receive the message. For example, an SMTP server used for outgoing messages normally relies on port 25. However, the Point-of-Presence (POP3) server used for incoming e-mail messages usually relies on port 110. Our browser typically uses port 80 to communicate with websites. However, secure websites (those that use https as a protocol, rather than http) rely on port 443 instead. 

3. Local hostname: The local hostname is the human-readable form of the combination of the host and port. For example, the website www.xyz.com might resolve to an address of 55.205.164.44:80 (where the first four numbers are the host address and the number after the colon is the port). Python takes care of these details behind the scenes for us, so normally we don’t need to worry about them. However, it’s nice to know that this information is available.

Connecting to an SMTP Server

We will follow the following steps to accomplish this process:


  1.     Create an SMTP object for connection to the server.
  2.     Log in to your account.
  3.     Define your message headers and login credentials.
  4.     Create a MIMEMultipart message object and attach the relevant headers to it, i.e. From, To,       and Subject.
  5.     Attach the message to the message MIMEMultipart object.
  6.     Finally, send the message.


In Python, the smtplib module defines an SMTP client session object that can be used to send mail to any Internet machine with an SMTP or ESMTP listener daemon.

This is how we create an SMTP object:

import smtplib

server = smtplib.SMTP(host='host_address',port=your_port)


A host address is the identifier for a connection to a server. The connection used to access a combination of a host address and a port is called a socket. Using the following program we can see hostnames and host addresses:

import socket
print(socket.gethostbyname('localhost'))
print(socket.gethostbyaddr('127.0.0.1'))
print(socket.gethostbyname('www.covrisolutions.com'))

When we run this program we get the following output:

127.0.0.1

('xyzsoft.com', ['127.0.0.1'])

198.23.81.104

------------------
(program exited with code: 0)

Press any key to continue . . .   

The socket library contains the functions we used in the program. The gethostbyname(“localhost”) outputs the host address. In our case, we see 127.0.0.1 as output because localhost is a standard hostname. The address, 127.0.0.1, is associated with the host name, localhost.

The socket.gethostbyaddr(“127.0.0.1”) gives a tuple as output. Instead of getting localhost as the name of the host, you get the name of your machine. We use localhost as a common name for the local machine, but when we specify the address, we get the machine name instead.

The socket.gethostbyname('www.covrisolutions.com') gives the address for my website.

A port is a specific entryway for a server location. The host address specifies the location, but the port defines where to get in. Access is always granted using a combination of the host address and the port. Let's see how ports work with the host address to provide server access:

import socket
print(socket.getaddrinfo('localhost', 110))
print(socket.getaddrinfo('www.covrisolutions.com', 80))
print(socket.getservbyport(25))

When we run this program we get the following output:

[(<AddressFamily.AF_INET6: 23>, 0, 0, '', ('::1', 110, 0, 0)), (<AddressFamily.A
F_INET: 2>, 0, 0, '', ('127.0.0.1', 110))]
[(<AddressFamily.AF_INET: 2>, 0, 0, '', ('198.23.81.104', 80))]
smtp

------------------
(program exited with code: 0)

Press any key to continue . . .

In socket.getaddrinfo(“localhost”, 110) the first value is the name of a host we want to obtain information about. The second value is the port on that host. The socket.getaddrinfo() method provides a useful method for determining how you can access a particular location. The socket.getservbyport() method provides the means to determine how a particular port is used.
Port 25 is always dedicated to SMTP support on any server. So, when we access 127.0.0.1:25, we’re asking for the SMTP server on localhost.

A hostname is simply the human-readable form of the host address. We don’t really understand 127.0.0.1 very well but understand localhost just fine. Type the following code and see the hostname:

import socket
print(socket.gethostname())
print(socket.gethostbyname(socket.gethostname()))

When we run this program we get the following output:

Python-PC
169.254.134.93

------------------
(program exited with code: 0)

Press any key to continue . . .

We get the name of the local system ,Python-PC and the IP address of the local system. The name of your system and IP will vary from mine, so your output will be different.

Sending mail

The domain name for the SMTP server will usually be the name of our email provider’s domain name, with smtp. in front of it. For example, Gmail’s SMTP server is at smtp.gmail.com. Once we have the domain name and port information for our email provider, create an SMTP object by calling smptlib.SMTP(), passing the domain name as a string argument, and passing the port as an integer argument.

The SMTP object represents a connection to an SMTP mail server and has methods for sending emails. For example, the following call creates an SMTP object for connecting to Gmail:

import smtplib
serverobj = smtplib.SMTP('smtp.gmail.com', 587)

The first argument is the server's hostname, the second is the port. The port used varies depending on the server. We need this SMTP object in order to call the methods that log us in and send emails. If the smptlib.SMTP() call is not successful, your SMTP server might not support TLS on port 587. In this case, we will need to create an SMTP object using smtplib.SMTP_SSL() and port 465 instead as shown below:

smtpObj = smtplib.SMTP_SSL('smtp.gmail.com', 465)

After we have the SMTP object, call its oddly named ehlo() method to “say hello” to the SMTP email server. This greeting is the first step in SMTP and is important for establishing a connection to the server. We have to call the ehlo() method first thing after getting the SMTP object or else the later method calls will result in errors. See the program below:

import smtplib

serverobj = smtplib.SMTP('smtp.gmail.com', 587)
print(serverobj.ehlo())

When we run this program we get the following output:

(250, b'smtp.gmail.com at your service, [183.83.43.8]\nSIZE 35882577\n8BITMIME\n
STARTTLS\nENHANCEDSTATUSCODES\nPIPELINING\nSMTPUTF8')

------------------
(program exited with code: 0)

Press any key to continue . . .

The first item in the returned tuple is the integer 250 (the code for “success” in SMTP), which indicates that the greeting succeeded.

If you are connecting to port 587 on the SMTP server (that is, you’re using TLS encryption), you’ll need to call the starttls() method next. This required step enables encryption for your connection. If you are connecting to port 465 (using SSL), then encryption is already set up, and you should skip this step. See the code below:

import smtplib

serverobj = smtplib.SMTP('smtp.gmail.com', 587)
print(serverobj.starttls())

When we run this program we get the following output:

(220, b'2.0.0 Ready to start TLS')
------------------
(program exited with code: 0)

Press any key to continue . . .

The starttls() puts our SMTP connection in TLS mode. The 220 in the return value tells us that the server is ready.

Logging in to the SMTP Server

After the SMTP server is set up, we can log in with our username (usually our email address) and email password by calling the login() method as shown in the syntax below:

serverobj.login("youremailusername", "password")

Let us pass a string of our email address as the first argument and a string of our password as the second argument. The 235 in the return value means authentication was successful. Python will raise an smtplib .SMTPAuthenticationError exception for incorrect passwords. See the program below:

import smtplib

serverobj = smtplib.SMTP('smtp.gmail.com', 587)
print(serverobj.login('vswami11@gmail.com', '1234556678))

When we run this program we get the following output:

Traceback (most recent call last):
  File "smtpdemo.py", line 4, in <module>
    print(serverobj.login('vswami11@gmail.com', '1234556678'))
  File "C:\Users\Python\AppData\Local\Programs\Python\Python36\lib\smtplib.py",
line 697, in login
    "SMTP AUTH extension not supported by server.")
smtplib.SMTPNotSupportedError: SMTP AUTH extension not supported by server.

------------------
(program exited with code: 1)

Press any key to continue . . .

This is because Google will not allow logging in via smtplib because it has flagged this type of login as "less secure". To solve this, go to https://www.google.com/settings/security/lesssecureapps while you're logged in to your Google account, and "Allow less secure apps". Once we change the settings and run the program we get the following output:

(235, b'2.7.0 Accepted')
------------------
(program exited with code: 1)

Press any key to continue . . .

Now that we are logged in to our email provider’s SMTP server, we can call the sendmail() method to actually send the email. The sendmail() method requires three arguments.

• Sender email address as a string (for the email’s “from” address)
• The recipient’s email address as a string or a list of strings for multiple recipients (for the “to” address)
• The email body as a string

The start of the email body string must begin with 'Subject: \n' for the subject line of the email. The '\n' newline character separates the subject line from the main body of the email.

The return value from sendmail() is a dictionary. There will be one key-value pair in the dictionary for each recipient for whom email delivery failed. An empty dictionary means all recipients were successfully sent the email. See the code below:

import smtplib

serverobj = smtplib.SMTP('smtp.gmail.com', 587)
serverobj.login('vswami11@gmail.com', '1234556678)
serverobj.sendmail('vswami11@gmail.com', 'satya@gmail.com','Subject: Update status.\nDear Satya, Please update project status. Sincerely,Vivek')
serverobj .quit()

When we run this program we get the following output:

(221, b'2.0.0 closing connection ko10sm23097611pbd.52 - gsmtp')

The quit() method must be called after sending the emails. The 221 in the return value means the session is ending.

The letter part of an e-mail is actually made of separate components as described:

Sender: The sender information tells you who sent the message. It contains just the e-mail address of the sender.

Receiver: The receiver information tells us who will receive the message. This is actually a list of recipient e-mail addresses. Even if we want to send the message to only one person, we must supply the single e-mail address in a list.

Message: Contains the information that we want the recipient to see. This information can include the following:

• From: The human-readable form of the sender.
• To: The human-readable form of the recipients.
• CC: Visible recipients who also received the message, even though they aren’t the primary targets of the message.
• Subject: The purpose of the message.
• Documents: One or more documents, including the text message that appears with the e-mail.

Python supports a number of methods of creating messages. However, the easiest and most reliable way to create a message is to use the Multipurpose Internet Mail Extensions (MIME) functionality that Python provides (and no, a MIME is not a silent person with white gloves who acts out in public).

There are also numerous forms of MIME that are all part of the email.mime module. The most often used are:

MIMEApplication: Provides a method for sending and receiving application input and output.
MIMEAudio: Contains an audio file
MIMEImage: Contains an image file
MIMEMultipart: Allows a single message to contain multiple subparts, such as including both text and graphics in a single message
MIMEText: Contains text data that can be in ASCII, HTML, or another standardized format.

We can create any sort of an e-mail message with Python, the easiest type to create is one that contains plain text. The lack of formatting in the content lets us focus on the technique used to create the message, rather than on the message content. The following program help shows how the message-creating process works:

from email.mime.text import MIMEText

msg = MIMEText("Howdy!")

msg['Subject'] = "Update status"

msg['From']='Vivek <vswami11@gmail.com>'

msg['To'] = 'Satya <satya@gmail.com>'

msg.as_string( )


The MIMEText() constructor requires message text as input. This is the body of our message, so it might be quite long. In this case, the message is relatively short — just a greeting. At this point, we assign values to standard attributes. The example shows the three common attributes that we always define: Subject, From, and To. The two address fields, From and To, contain both a human-readable name and the e-mail address. All you have to include is the e-mail address. When we run this program we get the following output:

Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: Update status
From: Vivek <vswami11@gmail.com>
To: Satya <satya@gmail.com>

Howdy!

------------------
(program exited with code: 0)

Press any key to continue . . .

The Content-Type reflects the kind of message you created, which is a plain-text message. The charset tells what kind of characters are used in the message so that the recipient knows how to handle them.

The MIME-Version specifies the version of MIME used to create the message so that the recipient knows whether it can handle the content. Finally, the Context-Transfer-Encoding determines how the message is converted into a bit stream before it is sent to the recipient.

Here I am ending today's topic. We'll continue with this topic in the next post. So till we meet next keep practicing and learning Python as Python is easy to learn!
Share:

0 comments:

Post a Comment