How to receive an email over smtpd and sockets - python

I have some code trying to receive an email sent from a server on a client. The email is definitively sent from the server to the client, and a SMTP server on the client should be able to receive this email. Here is my test implementation:
# define the SMTP server (with the real IP adress of the client of course)
server = smtpd.PureProxy(('XXX.XXX.XXX.XXX', 25), None)
inputs = [server]
outputs = []
message_queues = {}
readable, writable, exceptional = select.select(inputs, outputs, inputs)
# Only one socket in the list returned (there is exactly one)
socket = readable[0]
# Accept the connection or get it or whatever
connection, client_address = socket.accept()
# get the data
data = connection.recv(1024)
print data
After a considerably long time some data is received, which in no way resembles the content of the email. It is always
EHLO YYY.YYY.YYY.YYY
with the YYY the address of the server. I am no expert in SMTP and sockets, but what am I doing wrong to correctly receive the emai and its contents?
Thanks
Alex

The EHLO is part of the SMTP protocol exchange and it represents the client sending its greeting to your server which doesn't respond properly (because it doesn't respond at all). When the client gets tired of waiting for "a considerably long time" the session times out and your server shows what it received.
You seem to be confused as to which process is the server. The smtpd module creates servers or Mail Transport Agents, not clients. As noted in the smtpd documentation for SMTPServer:
Create a new SMTPServer object, which binds to local address
localaddr. It will treat remoteaddr as an upstream SMTP relayer. It
inherits from asyncore.dispatcher, and so will insert itself into
asyncore‘s event loop on instantiation.
You also seem to have the sense of localaddr and remoteaddr confused. The localaddr is not (as your comment claims) the address of the client, but where that server should accept connections from. You might want to try in place of your code:
server = smtpd.DebuggingServer(('localhost', 2525), None)
asyncore.loop()
Which can be tested with client code (in a separate process) of:
client smtplib.SMTP('localhost', 2525)
client.sendmail('from', 'to', 'body')
Finally, having a PureProxy with a remoteaddr of None, it if works at all, would proxy mail into nowhere which is probably not what you want in a proxy.

That is the proper start of the ESMTP protocol dialog. Your program needs to understand and handle at least the basic SMTP verbs; see RFC5321.

Related

Python sockets: How do I get the address a client is connected to?

I have some code that hosts a local server and when a user connects it will send them some html code, which works fine.
But I want it so if they connect to http://localhost:90/abc it will show something different. How can I get the exact url they connected to?
Here is my code:
import socket
sock = socket.socket()
sock.bind(('', 90))
sock.listen(5)
print("Listening...")
while True:
client, address = sock.accept()
print("Connection recieved: ", address)
print(The exact url they connected to.)
print()
client.send(b'HTTP/1.0 200 OK\r\n')
client.send(b"Content-Type: text/html\r\n\r\n")
client.send(b'<html><body><h1>Hello, User!</body></html>')
client.close()
sock.close()
I tried print(client.getpeername()[1]), but that gets the client ip, and if there is a similar way to get the ip they connected to it probably wont get the 'abc' part of the url.
Thanks in advance.
Socket's don't have a notion of URL, that's specific to the HTTP protocol which runs on top of a socket. For this reason, only part of the HTTP URL is even used in the creation of a socket.
|--1---|----2----|-3-|--4-|
http:// localhost :90 /abc
Specifies which protocol inside of TCP the URL uses
Specifies the remote host, either by IP address or hostname
Specifies the remote port and is optional
Specifies the path of the URL
Only parts 2 and 3 are actually known to a TCP socket though! This is because TCP is a very basic form of communication, HTTP adds a bunch of functionality on top of it like requests and responses and paths and so on.
Basically if you're implementing an HTTP server, knowing the /abc part is your job. Take a look at this example. The client actually sends the /abc part to the server, otherwise it has no way of knowing which path the request is for.
When the client connects to your server, it will send:
GET /abc HTTP/1.1
Host: localhost
more headers...
<blank line>
Your server needs to parse the GET line and extract /abc from that.

how to get input from html using python socket

I have a code to start a simple socket sever on localhost. However, I want it to display a html page when it is accessed through browser. The html will contain two text fields and submit button. When user enters text in text fields and clicks on submit button, I want the program to read from text fields. How Can I Do That?
The instant answer (I hope so) to your question is in the last section The Answer - and, if I have interpreted your question wrong, let me know in the comment section.
The confusion - You are confusing the fundamentals - to display a html page, you simply need a server (localhost in your case), and the browser will use the HTTP/HTTPS protocol to fetch that content/response/html page. In Python (almost same for other languages) there are two levels of access to network services:
Low-level via sockets.
Higher-level via application level network protocols, like HTTP, FTP, etc.
Sockets - in plain english it is a functionality (interface) provided by the machine's operating system to implement client and server (for the higher-level network protocols) like communication between the processes. These processes can be running on a same machine or both processes on physically apart machines (e.g. requesting a website using browser).
A typical socket client is (asking for the desired html from browser):
client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_sock.connect(("localhost", 80))
But to make it work you must already have server running (which will serve the html):
server_sock = socket.socket() # Create a socket object
server_sock.bind((localhost, 80)) # Bind to the port
server_sock.listen(5)
while True:
# lines for whatever we want server to do
The line server_sock.bind((localhost, 80)) has binded (assigned/allocated) the localhost:80 (a socket is basically 'host_name:port_number') to this server_sock i.e. any call/request to localhost:80 will be handled as per the lines in the above while True: block of the code above, can be a text response, HTML, etc.
Typical web scenario - We enter a website name www.google.com (which is resolved into an IP via DNS protocol - a whole another story) and hit enter, we'll get the Google's search homepage in response - Here you're the client, that is entering the website name and hitting enter is technically client_sock.connect('www.google.com', 80), and it only worked because on another (remote) machine/system/host they have server_socket binded and listening i.e.
server_sock.bind('machine's_IP', 80)
server_sock.listen(5)
while True:
#accept connections from outside
(client_socket, address) = server_socket.accept()
# here will be the lines which send us back the Google's
# homepage html as a response to our web request.
To sum-up, servers (webserver in your case) can be implemented using (almost) any programming languages e.g. python or C, etc, but the basis, the lowest layer, exactly where the data is passed between 2 processes whether on the same machine using locahost (loopback) or each process running on physically apart machine/host (typical web scenario ) via the HTTP (TCP) protocol rest upon sockets. Sockets are the fundamental building block from which HTTP, HTTPS, FTP, SMTP protocols (all of these are TCP-type protocols) are defined.
DNS, DHCP, VOIP protocols are UDP protocols but they too are built on top of sockets.
The Answer - To start, create a web_server.py and paste the following code (only to see how it works) and run the file as script i.e. from the file's location run "python
web_server.py" in command prompt/terminal:
#!/usr/bin/env python
import socket
host = 'localhost'
port = 80
server_sock = socket.socket(socket.AF_INET,\
socket.SOCK_STREAM) # Create a socket object
server_sock.bind((host , port)) # Bind to the port
print 'Starting server on', host, port
print 'The Web server URL for this would be http://%s:%d/' % (host, port)
server_sock.listen(5) # Now wait for client connection.
print 'Entering infinite loop; hit CTRL-C to exit'
while True:
# Establish connection with client.
client_sock, (client_host, client_port) = socket.socket.accept()
print 'Got connection from', client_host, client_port
client_sock.recv(1000) # should receive request from client. (GET ....)
client_sock.send('HTTP/1.0 200 OK\n')
client_sock.send('Content-Type: text/html\n')
client_sock.send('\n') # header and body should be separated by additional newline
# you can paste your 2 text field html here in the <body>
client_sock.send("""
<html>
<body>
<h1>Hello World</h1> this is my server!
</body>
</html>
""")
client_sock.close()
P.S. You have to implement a HTTP server (webserver) - which will definitely use the socket interface at the lowest level i.e.
server_sock.bind
server_sock.listen
server_sock.accept

how could a server send data to a client behind nat by udp in qt?

The server has a public IP, the client is behind a nat.
How could the client communicate with server by udp in qt?
The client will send some data to server first, then how could server reply to client?
The current code is this:
server:
self.udpSocketGet = QtNetwork.QUdpSocket()
self.udpSocketGet.bind(QtNetwork.QHostAddress.LocalHost, serverPort)
self.udpSocketGet.readyRead.connect(self.receive)
def receive(self):
while self.udpSocketGet.hasPendingDatagrams():
size = self.udpSocketGet.pendingDatagramSize()
if size > 0:
data, senderAddr, senderPort = self.udpSocketGet.readDatagram(size)
client:
def sentToServer(self,data):
udpSocketSend = QtNetwork.QUdpSocket()
udpSocketSend.writeDatagram(data.encode('utf-8'), serverAddress, serverPort)
The answer to your question goes beyond qt. Check out http://en.m.wikipedia.org/wiki/UDP_hole_punching and http://en.m.wikipedia.org/wiki/NAT_traversal
I am editing this answer after I looked back and found out that the server has a public IP address. In that case, the server will just have to respond to whatever IP address the request comes from. In case the client is communicating via NAT, the server will see the public address of the router and will be totally unaware that the actual client is behind that router.
Read Receiving a response through UDP
The bottom line is that you either have to use port mapping or UPNP.
See also https://superuser.com/questions/456812/nat-and-udp-replies
Again, the server code should not be concerned with NAT traversal. Either the client uses UPNP and the router has UPNP enabled. Or the router is configured to port forward or remember the source and destination IP addresses and ports of the packet originating from the client and properly farwards back the packets sent by the server.

send several messages in one connection, python socketIO

I'm using https://pypi.python.org/pypi/socketIO-client
ping = SocketIO(host, port)
ping.define(SIO)
ping.message(PING)
ping.wait(seconds=1)
namespace definition skipped.
this code works ok - I send one message and receive one from server.
But can't figure out how to send few messages in one connection and analyze responses in middle - I need to make short interactive session.
may be will be useful for someone someday...
i've figured out:
ping = SocketIO(host, port)
ping.define(SIO)
ping.message(PING)
ping.wait(seconds=1)
callResponceAnalyzer()
ping.message(MESSAGE1)
ping.wait(seconds=1)

xmpp with python: xmpp.protocol.InvalidFrom: (u'invalid-from', '')

cl = xmpp.Client('myserver.com')
if not cl.connect(server=('mysefver.com',5223)):
raise IOError('cannot connect to server')
cl.RegisterHandler('message',messageHandler)
cl.auth('myemail#myserver.com', 'mypassword', 'statusbot')
cl.sendInitPresence()
msgtext = formatToDo(cal, 'text')
message = xmpp.Message('anotheremail#myserver.com', msgtext)
message.setAttr('type', 'chat')
cl.send(message)
I get the following error message when I try to run it:
xmpp.protocol.InvalidFrom: (u'invalid-from', '')
Why is this happening :(
From the XMPP protocol specification:
If the value of the 'from'
address does not match the hostname represented by the Receiving
Server when opening the TCP connection (or any validated domain
thereof, such as a validated subdomain of the Receiving Server's
hostname or another validated domain hosted by the Receiving Server),
then the Authoritative Server MUST generate an stream
error condition and terminate both the XML stream and the underlying
TCP connection.
which basically means, that if the sender is not recognized by the xmpp-server, it'll reply with this message. XMPP supplies a registration mechanism: xmpp.features.register

Categories