How to send an Email with Arduino and Ethernet Shield (W5100)
Contents |
Used Hardware
- Arduino UNO R3
- Ethernet Shield with W5100 Wiznet Chip
Used Software
Bascom-AVR 2.0.7.6
Windows7 or 8
What you need to run the example
For the following example you need:
- Email account which supportSMTP Authentication (AUTH LOGIN) on Port 25
- Username and password Base64 encoded (you can use the Easy TCP/IP tool in Bascom-AVR to encode and decode)
- IP address of your smtp server (if you do not know it just open in Windows the DOS command window and ping the server)
- Your sender Email address and the receiver Email address
Don't use the Email Sub in the Do...Loop until you know what you are doing (Your mail provider could ban you if you send too much emails) !
This example use the base structure from here: http://wiki.mcselec.com/Getting_started_with_Arduino_UNO_R3_and_Ethernet_Shield_(W5100)
The focus of this article is Email and not other topics which are already descibed in other articels in this WIKI.
You need to change the * (asterisk) !
When you send the Email as HTML (with the Link) it might end up in your spam folder. So check also your spam folder for this email sent in HMTL format !
' Send Email with Arduino Ethernet (W5100) ' Tested with GMX 'Use Hardware: ' - Arduino UNO R3 ' - Arduino Ethernet Shield with W5100 Wiznet Chip ' NTP Server IP address (here you can change the NTP server of your choice) Const Ntp1 = 192 : Const Ntp2 = 53 : Const Ntp3 = 103 : Const Ntp4 = 108 ' Example NTP Server = 192.53.103.108 Const Use_ping = 1 'use PING NTP server for checking NTP server availability before move on $regfile = "m328pdef.dat" $crystal = 16000000 '16MHz $hwstack = 100 $swstack = 100 $framesize = 400 config submode = new Config Com1 = 57600 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0 '------------------------------------------------------------------------------- ' Watchdog '------------------------------------------------------------------------------- config watchdog = 4096 Start watchdog '------------------------------------------------------------------------------- ' Server Variables '------------------------------------------------------------------------------- Dim Ip_sntp_server As Long 'assign the IP number of a SNTP server Ip_sntp_server = Maketcp(ntp1 , Ntp2 , Ntp3 , Ntp4) 'assign IP of NTP SERVER Wait 2 'Time to start the Debug Terminal after flashing reset watchdog Print Print "-----START Arduino UNO R3 + Ethernet Shield EMAIL DEMO-----" '------------------------------------------------------------------------------- ' Network Hardware '------------------------------------------------------------------------------- Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = Low , Phase = 0 , Clockrate = 4 , Noss = 0 Spiinit Enable Interrupts 'Here you need MAC address, the ip address you like to use, subnet mask, gateway and localport Config Tcpip = Noint , _ Mac = 1.1.94.127.1.255 , _ Ip = 192.168.2.254 , _ Submask = 255.255.255.0 , _ Gateway = 192.168.2.1 , _ Localport = 1000 , _ Tx = $55 , Rx = $55 , _ Chip = W5100 , _ Spi = 1 '------------------------------------------------------------------------------- ' Config Clock '------------------------------------------------------------------------------- Dim Local_time As Long Dim New_second As Bit dim second_counter as byte Config Date = Dmy , Separator = . Config Clock = User Config Timer1 = Timer , Prescale = 256 On Timer1 Timer_irq Saveall 'the SAVEALL option is NEEDED ! Const Timer_preload = 3036 Enable Timer1 '------------------------------------------------------------------------------- ' SMTP Email Variables '------------------------------------------------------------------------------- Dim Smtp_sock As Byte Dim Tcp_var As Byte Dim email_string As String * 130 Dim length as byte Const Smtp_email_socket = 1 'Socket Number for SMTP '------------------------------------------------------------------------------- ' UDP Variables '------------------------------------------------------------------------------- Dim Idx As Byte ' socket number Dim Result As Word ' result Dim S(255) As Byte Dim R(255) As Byte Dim Sstr As String * 255 Dim Temp As Byte , Temp2 As Byte ' temp bytes Dim Ip As Long '------------------------------------------------------------------------------- ' PING NTP SERVER to check if NTP server is available '------------------------------------------------------------------------------- #if Use_ping = 1 Dim J As Byte , Res As Byte Dim Ii As Byte Dim Ping_check_ok As Bit Reset Watchdog ' FILL PING ARRAY S(1) = 8 'type is echo S(2) = 0 'code S(3) = 0 ' for checksum initialization S(4) = 0 ' checksum S(5) = 0 ' a signature can be any number S(6) = 1 ' signature S(7) = 0 ' sequence number - any number S(8) = 1 S(9) = 65 Dim W As Word At S + 2 Overlay 'same as dta(3) and dta(4) Dim B As Byte W = Tcpchecksum(s(1) , 9) ' calculate checksum and store in dta(3) and dta(4) 'Ip = Maketcp(192.53.103.108) 'try to check this google server Print "PING NTP Server : " ; Ip2str(ip_sntp_server) 'Print "Socket " ; Idx ; " " ; Idx Setipprotocol Idx , 1 'set protocol to 1 'the protocol value must be set BEFORE the socket is openend Idx = Getsocket(idx , Sock_ipl_raw , 5000 , 0) 'RAW Socket ' We try the PING 3 times (but if we get an answer we exit the for loop) Do Incr Ii Result = Udpwrite(ip_sntp_server , 7 , Idx , S(1) , 9) 'write ping data ' Print "Ping Number : " ; ii Waitms 200 ' depending on the hops, speed, etc Result = Socketstat(idx , Sel_recv) 'check for data ' Print "REC:" ; Result If Result >= 11 Then Res = Tcpread(idx , R(1) , Result) 'get data with TCPREAD !!! ' Print "DATA RETURNED :" ; Res '( ' For J = 1 To Result Print R(j) ; " " ; Next Print ') Print "PING OK --> Exit Do..Loop" Set Ping_check_ok Exit Do ' If we can an answer from NTP Server exit do ... loop Else Print "NTP Server not available" End If Waitms 100 Loop Until Ii = 3 Ii = 0 #else Dim Ping_check_ok As Bit Ping_check_ok = 1 #endif '------------------------------------------------------------------------------- ' SNTP '------------------------------------------------------------------------------- If Ping_check_ok = 1 Then 'When the NTP Serverer responded to PING 'we need to get a socket first 'note that for UDP we specify sock_dgram Idx = Getsocket(idx , Sock_dgram , 1000 , 0) ' get socket for UDP mode, specify port Print "Socket " ; Idx ; " " ; Idx Local_time = Sntp(idx , Ip_sntp_server) ' get time from SNTP server Print "Local_time = " ; Local_time If Local_time < 100 Then 'try it again Wait 1 Local_time = Sntp(idx , Ip_sntp_server) ' get time from SNTP server Print "Second try ; Local_time = " ; Local_time End If Local_time = Local_time + 3600 ' (UTC/GMT) time + 3600 Print Date(local_time) ; Spc(3) ; Time(local_time) End If '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ' + ' + SUB NAME: Send_Email() ' + ' + DESCRIPTION: Send Email ' + ' + ' + RETURN: None ' + ' + NOTES: None ' + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ' Sub Send_Email(byval Send_html As Byte) ' 0 = send Text, 1 = send HTML '---------------------[SEND EMAIL SMTP]----------------------------------------- 'for SMTP Email first we need a socket idx = Getsocket(smtp_email_socket , Sock_stream , 4086 , 0) If idx = 255 Then print "SMTP Email Getsocket Error" '( result = Socketstat(idx , Sel_control) Select Case result Case Sock_closed : print "Sock_closedr" Case Sock_arp : print "SOCK_ARP" Case Sock_listen : print "SOCK_LISTEN" Case Sock_synsent : print "SOCK_SYNSENT" Case Sock_synrecv : print "SOCK_SYNRECV" Case Sock_established : print "SOCK_ESTABLISHED" Case Sock_close_wait : print "SOCK_CLOSE_WAIT" Case Sock_last_ack : print "SOCK_LAST_ACK" Case Sock_fin_wait : print "SOCK_FIN_WAIT" Case Sock_closing : print "SOCK_CLOSING" Case Sock_time_wait : print "SOCK_TIME_WAIT" Case Sock_init : print "SOCK_INIT" Case Sock_udp : print "SOCK_UDP" Case Sock_raw : print "SOCK_RAW" Case Sock_macraw : print "SOCK_MACRAW" Case Sock_ppoe : print "SOCK_PPOE" End Select ') 'connect to smtp server result = Socketconnect(idx , 213.165.64.21 , 25) ' smtp server and SMTP port 25 ' ^socket ' ^ ip address of the smtp server ' ^ port 25 for smtp print "Connecting to GMX Email Server: " ; " 213.165.64.21 Port 25 " print "Socketconnect Status = " ; result If result = 1 Then print "ERROR connecting to 213.165.64.21 Port 25" Reset Watchdog Do result = Socketstat(idx , 0) ' get socket status Loop Until result = Sock_established print "SMTP = " ; "SOCK_ESTABLISHED" Reset Watchdog Do Tcp_var = Tcpread(idx , email_string) ' get response from SMTP server If Left(email_string , 3) = "220" Then print "Server Answer = " ; email_string Exit Do End If 'The Watchdog will restart the micro in case of no or wrong answer Loop print "Send " ; "HELO Arduino Ethernet{013}{010}" Tcp_var = Tcpwrite(idx , "HELO Arduino Ethernet{013}{010}" ) ' send username print Tcp_var ; " bytes written" ' number of bytes actual send Do Tcp_var = Tcpread(idx , email_string) ' get response from SMTP server If Left(email_string , 3) = "250" Then print "Server Answer = " ; email_string Exit Do End If 'The Watchdog will restart the micro in case of no or wrong answer Loop Reset Watchdog print "Send " ; "AUTH LOGIN{013}{010}" Tcp_var = Tcpwrite(idx , "AUTH LOGIN{013}{010}" ) 'authentication login Do Tcp_var = Tcpread(idx , email_string) ' get response from SMTP server If Left(email_string , 3) = "334" Then print "Server Answer = " ; email_string Exit Do End If 'The Watchdog will restart the micro in case of no or wrong answer Loop Reset Watchdog 'The username must be Base64 encoded (and add the CR + LF)! Tcp_var = Tcpwrite(idx , "**********************=={013}{010}" ) 'USERNAME Do Tcp_var = Tcpread(idx , email_string) ' get response from SMTP server If Left(email_string , 3) = "334" Then print "Server Answer = " ; email_string Exit Do End If 'The Watchdog will restart the micro in case of no or wrong answer Loop Reset Watchdog 'The password must be Base64 encoded (and add the CR + LF) ! Tcp_var = Tcpwrite(idx , "********************=={013}{010}" ) 'PASSWORD Do Tcp_var = Tcpread(idx , email_string) ' get response from SMTP server If Left(email_string , 3) = "235" Then print "Server Answer = " ; email_string Exit Do End If 'The Watchdog will restart the micro in case of no or wrong answer Loop Reset Watchdog 'Your Email address Tcp_var = Tcpwrite(idx , "MAIL FROM: *********@***.com{013}{010}") Do Tcp_var = Tcpread(idx , email_string) ' get response from SMTP server If Left(email_string , 3) = "250" Then print "Server Answer = " ; email_string Exit Do End If 'The Watchdog will restart the micro in case of no or wrong answer Loop Reset Watchdog 'The Email address you want to send the message to Tcp_var = Tcpwrite(idx , "RCPT TO: ******@*****.com{013}{010}") Do Tcp_var = Tcpread(idx , email_string) ' get response from SMTP server If Left(email_string , 3) = "250" Then print "Server Answer = " ; email_string Exit Do End If 'The Watchdog will restart the micro in case of no or wrong answer Loop Reset Watchdog Tcp_var = Tcpwrite(idx , "DATA{013}{010}" ) Do Tcp_var = Tcpread(idx , email_string) ' get response from SMTP server If Left(email_string , 3) = "354" Then print "Server Answer = " ; email_string Exit Do End If 'The Watchdog will restart the micro in case of no or wrong answer Loop Reset Watchdog Tcp_var = Tcpwrite(idx , "FROM: ********@***.de{013}{010}") Tcp_var = Tcpwrite(idx , "TO: *******@****.com{013}{010}") Tcp_var = Tcpwrite(idx , "SUBJECT: Arduino Ethernet Bascom{013}{010}") Tcp_var = Tcpwrite(idx , "X-Mailer: BASCOM SMTP{013}{010}") If Send_html = 1 Then '----------------------Send the Email as HTML --------------------------- Tcp_var = Tcpwrite(idx , "Mime-Version: 1.0;{013}{010}") Tcp_var = Tcpwrite(idx , "Content-Type: text/html; charset={034}ISO-8859-1{034};{013}{010}") Tcp_var = Tcpwrite(idx , "Content-Transfer-Encoding: 7bit;{013}{010}") Tcp_var = Tcpwrite(idx , "{013}{010}") 'Empty line to switch to body Tcp_var = Tcpwrite(idx , "<html>{013}{010}") Tcp_var = Tcpwrite(idx , "<body>{013}{010}") Tcp_var = Tcpwrite(idx , "<h2>The Link to Bascom Forum !</h2>{013}{010}") Tcp_var = Tcpwrite(idx , "Here is it: <a href={034}http://www.mcselec.com/index2.php?option=com_forum&Itemid=59{034}>Bascom Forum</a>{013}{010}") Tcp_var = Tcpwrite(idx , "<p>Best Regards,</p>{013}{010}") Tcp_var = Tcpwrite(idx , "<p>Arduino Ethernet Bascom</p>{013}{010}") Tcp_var = Tcpwrite(idx , "</body>{013}{010}") Tcp_var = Tcpwrite(idx , "</html>{013}{010}") Tcp_var = Tcpwrite(idx , ".{013}{010}") Else '-----------------------Send only TEXT----------------------------------- Tcp_var = Tcpwrite(idx , "{013}{010}") 'Empty line to switch from subject to body Tcp_var = Tcpwrite(idx , "This is a test email from BASCOM-AVR SMTP{013}{010}") Tcp_var = Tcpwrite(idx , "Arduino Ethernet Bascom{013}{010}") email_string = "Timestamp = " + time$ + " / " + date$ + "{013}{010}" length = len(email_string) Tcp_var = Tcpwrite(idx , email_string, length) Tcp_var = Tcpwrite(idx , ".{013}{010}") ' end with a single dot end if Reset Watchdog Do Tcp_var = Tcpread(idx , email_string) ' get response from SMTP server If Left(email_string , 3) = "250" Then print "Server Answer = " ; email_string '--> 250 2.6.0 Message accepted Exit Do End If 'The Watchdog will restart the micro in case of no or wrong answer Loop print "Send " ; "QUIT{013}{010}" Tcp_var = Tcpwrite(idx , "QUIT{013}{010}") Do Tcp_var = Tcpread(idx , email_string) ' get response from SMTP server If Left(email_string , 3) = "221" Then print "Server Answer = " ; email_string Exit Do End If 'The Watchdog will restart the micro in case of no or wrong answer Loop Print "Close Socket" Closesocket Idx ' close the server connection End Sub reset watchdog 'Here we send the email call Send_Email(0) 'Send text Email wait 2 : reset watchdog call Send_Email(1) 'Send Email in HTML Do If New_second = 1 Then Reset New_second reset watchdog 'Do something every second ...... print "Tick" incr second_counter if second_counter = 180 then second_counter = 0 'Do something every 3 minutes ...... end if End If Loop End Timer_irq: Incr Local_time Time$ = Time(local_time) Date$ = Date(local_time) Set New_second Return Getdatetime: Return Settime: Return Setdate: Return
Terminal Ouput of Example
-----START Arduino UNO R3 + Ethernet Shield EMAIL DEMO-----
PING NTP Server : 192.53.103.108
Ping Number : 1
PING OK --> Exit Do..Loop
Socket 0 0
Local_time = 416239374
10.03.13 15:02:54
Connecting to GMX Email Server: 213.165.64.21 Port 25
Socketconnect Status = 0
SMTP = SOCK_ESTABLISHED
Server Answer = 220 mail.gmx.net GMX Mailservices ESMTP {mp033}
Send HELO Arduino Ethernet
23 bytes written
Server Answer = 250 mail.gmx.net GMX Mailservices {mp033}
Send AUTH LOGIN
Server Answer = 334 VXNlcm5hbWU6
Server Answer = 334 UGFzc3dvcmQ6
Server Answer = 235 2.7.0 Go ahead {mp033}
Server Answer = 250 2.1.0 ok {mp033}
Server Answer = 250 2.1.5 ok {mp033}
Server Answer = 354 mail.gmx.net Go ahead {mp033}
Server Answer = 250 2.6.0 Message accepted {mp033}
Send QUIT
Server Answer = 221 2.0.0 GMX Mailservices {mp033}
Close Socket
Connecting to GMX Email Server: 213.165.64.21 Port 25
Socketconnect Status = 0
SMTP = SOCK_ESTABLISHED
Server Answer = 220 mail.gmx.net GMX Mailservices ESMTP {mp033}
Send HELO Arduino Ethernet
23 bytes written
Server Answer = 250 mail.gmx.net GMX Mailservices {mp033}
Send AUTH LOGIN
Server Answer = 334 VXNlcm5hbWU6
Server Answer = 334 UGFzc3dvcmQ6
Server Answer = 235 2.7.0 Go ahead {mp033}
Server Answer = 250 2.1.0 ok {mp033}
Server Answer = 250 2.1.5 ok {mp033}
Server Answer = 354 mail.gmx.net Go ahead {mp033}
Server Answer = 250 2.6.0 Message accepted {mp033}
Send QUIT
Server Answer = 221 2.0.0 GMX Mailservices {mp033}
Close Socket
Tick
Tick
Tick
Tick
Tick
Tick
Tick
Tick
Tick
Telnet Exercise with sending an Email (if you encounter a problem)
The AUTH LOGIN smtp command is used to login to the smtp server with Username and password (both must be sent Base64 encoded).
You can use the Easy TCP/IP Tool in Bascom-AVR to decode or encode Base64.
You can check all the single steps of the SMTP server communication with TELNET in a manual procedure:
1. Enabling Telnet Client in Windows 7
http://social.technet.microsoft.com/wiki/contents/articles/910.enabling-telnet-client-in-windows-7.aspx
2. Start the DOS command window in Windows 7 and type telnet and return
3. Then you see: Microsoft Telnet> in the DOS command window.
4. Now type (we use as example GMX with Port 25): open smtp.gmx.net 25 (25 is the port number)
5. The answer from the SMTP server will be: 220 mail.gmx.net GMX Mailservices ESMTP {mpXXX}
6. Then type: AUTH LOGIN
7. The answer from the SMTP server will be: 334 VXNlcm5hbWU6
8. If you decode the VXNlcm5hbWU6 for example with the Easy TCP/IP Tool in Bascom-AVR
you will notice that the decoded text is Username:
9. You need now to type in the username Base64 encoded (which is usually your Email address Base64 encoded)
10. After this the SMTP server ask for the password (also Base64 encoded)
11. If you type in the wrong username or password the server's answer is 535 5.7.0 Incorrect username or password {mpXXX}
12. The correct username and password will be answerd by: 235 2.7.0 Go ahead {mpXXX}
13. ...
14. You can start the Email content with DATA and end it with <CR><LF>.<CR><LF> which is in Bascom {013}{010}.{013}{010}
SMTP Server Reply Codes
Code Description
211 System status, or system help reply.
214 Help message.
220 Domain service ready.Ready to start TLS.
221 Domain service closing transmission channel.
250 Ok , Queuing For Node Node Started.requested Mail Action Okay , Completed.
251 Ok , No Messages Waiting For Node Node.user Not Local , Will Forward To Forwardpath.
252 OK, pending messages for node node started.Cannot VRFY user (e.g., info is not local), but will take message for this user and attempt delivery.
253 OK, messages pending messages for node node started.
354 Start mail input; end with <CRLF>.<CRLF>.
355 Octet-offset is the transaction offset.
421 Domain Service Not Available , Closing Transmission Channel.
432 A password transition is needed.
450 Requested mail action not taken: mailbox unavailable.ATRN request refused.
451 Requested action aborted: local error in processing.Unable to process ATRN request now
452 Requested action not taken: insufficient system storage.
453 You have no mail.
454 TLS not available due to temporary reason.Encryption required for requested authentication mechanism.
458 Unable to queue messages for node node.
459 Node node not allowed: reason.
500 Command not recognized: command.Syntax error.
501 Syntax error, no parameters allowed.
502 Command not implemented.
503 Bad sequence of commands.
504 Command parameter not implemented.
521 Machine does not accept mail.
530 Must issue a STARTTLS command first.Encryption required for requested authentication mechanism.
534 Authentication mechanism is too weak.
538 Encryption required for requested authentication mechanism.
550 Requested action not taken: mailbox unavailable.
551 User not local; please try forwardpath.
552 Requested mail action aborted: exceeded storage allocation.
553 Requested action not taken: mailbox name not allowed.
554 Transaction failed.
Author
MAK3