Python smtplib sending mail using docmd - python

I currently have an smtplib client using sendmail. I need to trap the message id given to the sent message by the receiving server - and from what I've read here I need to use smtplib's docmd command. What I've worked out so far is fairly easy:
import smtplib
svr = smtplib.SMTP("localhost",26)
r = svr.docmd("ehlo", "me")
r = svr.docmd("mail from:","me#home.com")
r = svr.docmd("rcpt to:","you#work.com")
r = svr.docmd("data","")
But now when I try to do svr.docmd("send","Hello there") it just hangs? Similarly, I assume I should do r = svr.docmd("send",".") to send the terminating "." character to send the mail, and get the server response (in theory including msg id!) as part of the returned tuple?
Would really appreciate it if someone could point me at where I'm going wrong in these final steps?
Or am I completely misunderstanding - is using docmd NOT the way to get the server response when the mail is sent? If I am wrong, what should I be doing instead?

smtplibmodule cannot work like that. It is a higher level library and you should not try to send simple mail with docmd. docmd only helps to pass special commands. You should simply use :
svr.sendmail('me#home', 'you#work', 'msg')
If you really want to do it the hard way, you should send all the data in only single docmd :
...
r = svr.docmd("data")
r = svr.docmd("line 1\r\nline 2\r\n.\r\n")
That way it a a complete command that receives its SMTP response
Edit :
The return of low-level commands is the content of the SMTP response. The RFC 2821 specifies that this replies consist in a 3 digit number followed by an textual explaination. It can be multiline if the number is followed by a -. But all that is hidden from you by smtplib module. The main point of interest if you use low level commands is first digit from the number :
1yz Positive Preliminary reply
2yz Positive Completion reply
3yz Positive Intermediate reply
4yz Transient Negative Completion reply
5yz Permanent Negative Completion reply
If it is 4 or 5 the command was rejected, 1,2, or 3 it was successful
If you use directly sendmail command, if you do not get an exception, the mail was successfuly received by the server and accepted for at least on recipient. The return value is a dictionary, with one entry for each recipient that was refused. Each entry contains a tuple of the SMTP error code and the accompanying error message sent by the server (extract from the module documentation).
I advice you to use the sendmail command unless you want to learn the SMTP protocol or have other special requirement.

Related

FIX Protocol : 35=8 Execution Report coming in log file but not passing through fromApp()/onMessage()

I am sending the below FIX sample message using the quickfix python library.
8=FIX4.4,9=225,35=D,34=3,49=AB,52=20220919-07:43:13.917,56=CD,11=44536,15=EUR,17=00002,21=3,37=44536,38=918293,40=2,44=0,48=11,54=1,55=EURUSD,58=LKLA,
59=0,60=20220919-07:43:13.917,64=20220921,78=1,79=LKLA,80=918293,448=f88f2f6277,10=097
Immediately after sending the message, I am getting the message back from the server with 35=8 tag. Please see the below the message
8=FIX4.4,9=201,35=8,49=CD,56=AB,34=2,52=20220919-07:56:05.330,11=44536,15=EUR,38=918293,40=2,54=1,55=EURUSD,59=0,64=20220921,
6=0.,14=0,17=5249952-1024823399,31=0.,32=0,37=5249952-1024823399,39=0,150=0,151=918293,10=047
(tags 35=Execution report, 39= New, 150 = New)
When the trade is executed in FXALL, and when I send new FIX messages again, All the executed trades are logged in messages.current.log file. I am getting the below message in log file but not in fromApp.
8=FIX4.4,9=520,35=8,49=CD,56=AB,34=3,52=20220919-11:24:03.145,39=2,37=152648401_0_0,11=44536,17=152648401_0_0,150=F,1=test#bc,64=20220921,55=EUR/USD,40=1,15=EUR,31=0.9997,194=0.9997,195=0.,151=0,6=0.9997,75=20220919,119=918017.51,120=USD,78=1,79=LKLA ,80=918293,1908=1,1909=5493004U2OZSNMN2ML88852648401L0A0,1911=1,60=20220919-11:12:47,453=2,448=test#bc,447=C,452=11,448=BANK2,447=B,452=1,6977=1,6978=BANK2,6979=0.99965,
6980=0.00,6981=0.99965,6982=0.9997,6983=0.00,6984=0.9997,54=1,14=918293,38=918293,32=918293,7055=44536_0_0,10=124,
(tags 35=Execution report, 39=Filled, 150=Filled)
How do i get the above message(35=8 filled) in Onmessage/fromApp.
Is there any way/message that i can send to get all the executed trades till now?
something like:
8=FIX.4.4|9=158|35=8|34=3|49=AB|52=20220912-09:55:25.467|56=CD|6=0|11=44536|14=986604|17=00002|31=0|32=986604|37=00001|38=986604|39=2|54=1|55=EURUSD|58=44536|150=2|151=0|10=18
Thanks.
The reasons I know are:
Your lib might be ignoring PossDupFlag(43=Y) messages (IgnorePossDupResendRequests=Y configured if you are using QuickfixN - http://quickfixn.org/tutorial/configuration.html)
Your system is rejecting the messages that don't match against the DataDictionary used by the other counter party
Please check if your app is sending Reject messages (35=3) to the counter party immediately after receiving an ExecutionReport (35=8). If so, it will indicate that you might have some issues at your DataDictionary file. In this case your app will reject the messages and the ExecutionReport (35=8) will not be captured by your fromApp method.
My suggestion is:
check if you are sending 35=3 to the counter party. If it is true, check the 35=3 information, you will notice the reason the message was rejected
double check your data dictionary against the counter party's dictionary
double check if your session configuration file contains the entries below (considering quickfixJ)
ValidateFieldsOutOfOrder=N
ValidateFieldsHaveValues=N
ValidateUserDefinedFields=N
ValidateUnorderedGroupFields=N
AllowUnknownMsgFields=Y

Getting no response from the server when sending market orders via the FIX API

I am trying to send a purchase order, but I am not receiving a response from the server. The session is correct, and I am connected to port 5202. The python code is:
mdr = fix.Message()
mdr.getHeader().setField(fix.BeginString(fix.BeginString_FIX44))
mdr.getHeader().setField(fix.MsgType(fix.MsgType_NewOrderSingle))
mdr.getHeader().setField(fix.TargetSubID('TRADE'))
mdr.getHeader().setField(fix.SenderSubID('TRADE'))
mdr.setField(fix.ClOrdID(str(str(self.genExecID())))
mdr.setField(fix.HandlInst('1')))
mdr.setField(fix.Side('1'))
mdr.setField(fix.Symbol('1'))
mdr.setField(fix.OrderQty(0.01))
mdr.setField(fix.Currency('EUR'))
mdr.setField(fix.TimeInForce('1'))
mdr.setField(fix.OrdType('1'))
trstime = fix.TransactTime()
trstime.setString(datetime.utcnow().strftime('%Y%m%d-%H:%M:%S.%f')[:-3])
mdr.setField(trstime)
fix.Session.sendToTarget(mdr, self.sessionID)
And the message it generates is:
8=FIX.4.4☺9=158☺35=D☺34=2☺49=demo.ctrader.3449248☺50=TRADE☺52=20220310-10:37:36.000☺56=CSERVER☺57=TRADE☺11=1☺15=EUR☺21=1☺38=0.01☺40=1☺54=1☺55=1☺59=1☺60=20220310-10:37:36.898☺10=130☺
Does anyone miss any fields or see any errors in the message. Thank you very much.
This might be a bit late...but I had a similar issue and changed my fix message to the following:
Tag 50 (sendersubid) - Should be a random string of characters for that particular session you are logging in with and should be changed with every new login. If you log in multiple times with the same sendersubid, I think the server rejects.
Tag 38 (lot size) - you used "0.01". Try instead "1000"
"CSERVER" should be "cServer"
hope it helps

String ">>>>>>>" getting messed up while sending a email

I am trying to send an email as below using conflictedblocks_string,string >>>>>>> gets printed fine but gets messedup when sending as email, can anyone explain why and how to fix it?
conflictedblocks_string = ''
conflictedblocks = {'README': '<<<<<<< HEAD\nTBD1\n=======\nTRP1\n>>>>>>> b9bde66...\n', 'DO_NOT_READ': 'Probably a new file'}
for key,value in conflictedblocks.items():
conflictedblocks_string += key + ":" + "\n" + value + "\n"
print conflictedblocks_string --> `>>>>>>>` prints fine
sendemail(conflictedblocks_string ) --> `>>>>>>>` messed up while sending email
sendemail api snippet:
body = '''%s''' % (data)
msg = MIMEText(body)
mail = smtplib.SMTP('company.apple.com', 25)
mail.sendmail(sender, receivers, msg.as_string())
CURRENT OUTPUT:-
EXPECTED OUTPUT:-
README:
<<<<<<< HEAD
TBD1
=======
TRP1
>>>>>>> b9bde66...
DO_NOT_READ:
Probably a new file
There's nothing at all wrong with your code. Or the mail servers. The email has >>>>>>> in it, just as you intended.
However, many mail programs and webmail systems translate > at the start of a line into an indent marker when formatting mail for viewing.
Traditionally, > at the start of a line is how you mark that you're quoting someone inline. So, to make email threads earlier to read, mail clients turn those quotes into something that looks more like quotes.
For example, this is a traditional plain-text email:
John shouted:
> My father said:
>> No! You will BE KILL BY DEMONS
> No! I must kill the demons
The radio said:
> No, John, You are the demons.
And then John was a zombie.
An email client might render it like this:
John shouted:
My father said:
No! You will BE KILL BY DEMONS
No! I must kill the demons
The radio said:
No, John, You are the demons.
And then John was a zombie.
There's no universal workaround that will work for every client, because every client has its own heuristic code that messes things up. But there a few things that often work.
First, if you send both HTML and plain-text versions of your mail, most of the fancy clients that would have treated > as formatting will display the HTML instead, which you can format however you want, while clients that refuse to display HTML will probably also not try to do anything with the >.
Another option is to put the diff you're trying to include as an attachment, instead of the body. You can try to mark it as an inline attachment, in hopes that some clients will show it without making the user click on the attachment and open it, but I don't think too many clients like inline plain-text attachments.
Prefixing the line with a space often works, like this:
<<<<<<< HEAD
TBD1
=======
TRP1
>>>>>>> b9bde66
But of course the person reading the mail will have to know about the extra space—and if they're copying and pasting, they'll have to remember to remove it.
If that works, prefixing every line in the email, or just every line in the diff, with a space, would also work. It doesn't look quite as ugly, but if anything it can cause more copy-paste headaches.
It is unrelated to Python and unrelated to mail sending...
Historically, when mails were just plain ASCII text, the > character was used (as a convention) in responses to mark citations from the original mail.
With HTML and richer character sets, the citations are now indicated with vertical bars | and different colors.
In order to give a nicer user experience, mail readers interpret > characters in plain text mails and format them as modern citation marks.
So:
you mail was correctly sent and contains the correct >
the culprit is your mail reader which (wrongly here) formats initial > in a body line as if it was a citation

Python sending mutliple strings using socket.send() / socket.recv()

I am trying to send multiple strings using the socket.send() and socket.recv() function.
I am building a client/server, and "in a perfect world" would like my server to call the socket.send() function a maximum of 3 times (for a certain server command) while having my client call the socket.recv() call 3 times. This doesn't seem to work the client gets hung up waiting for another response.
server:
clientsocket.send(dir)
clientsocket.send(dirS)
clientsocket.send(fileS)
client
response1 = s.recv(1024)
if response1:
print "\nRecieved response: \n" , response1
response2 = s.recv(1024)
if response2:
print "\nRecieved response: \n" , response2
response3 = s.recv(1024)
if response3:
print "\nRecieved response: \n" , response3
I was going through the tedious task of joining all my strings together then reparsing them in the client, and was wondering if there was a more efficient way of doing it?
edit:
My output of response1 gives me unusual results. The first time I print response1, it prints all 3 of the responses in 1 string (all mashed together). The second time I call it, it gives me the first string by itself. The following calls to recv are now glitched/bugged and display the 2nd string, then the third string. It then starts to display the other commands but as if it was behind and in a queue.
Very unusual, but I will likely stick to joining the strings together in the server then parsing them in the client
You wouldn't send bytes/strings over a socket like that in a real-world app.
You would create a messaging protocol on-top of the socket, then you would put your bytes/strings in messages and send messages over the socket.
You probably wouldn't create the messaging protocol from scratch either. You'd use a library like nanomsg or zeromq.
server
from nanomsg import Socket, PAIR
sock = Socket(PAIR)
sock.bind('inproc://bob')
sock.send(dir)
sock.send(dirS)
sock.send(fileS)
client
from nanomsg import Socket, PAIR
sock = Socket(PAIR)
sock.bind('inproc://bob')
response1 = sock.recv()
response2 = sock.recv()
response3 = sock.recv()
In nanomsg, recv() will return exactly what was sent by send() so there is a one-to-one mapping between send() and recv(). This is not the case when using lower-level Python sockets where you may need to call recv() multiple times to get everything that was sent with send().
TCP is a streaming protocol and there are no message boundaries. Whether a blob of data was sent with one or a hundred send calls is unknown to the receiver. You certainly can't assume that 3 sends can be matched with 3 recvs. So, you are left with the tedious job of reassembling fragments at the receiver.
One option is to layer a messaging protocol on top of the pure TCP stream. This is what zeromq does, and it may be an option for reducing the tedium.
The answer to this has been covered elsewhere.
There are two solutions to your problem.
Solution 1:
Mark the end of your strings. send(escape(dir) + MARKER) Your client then keeps calling recv() until it gets the end-of-message marker. If recv() returns multiple strings, you can use the marker to know where they start and end. You need to escape the marker if your strings contain it. Remember to escape on the client too.
Solution 2:
Send the length of your strings before you send the actual string. Your client then keeps calling recv() until its read all the bytes. If recv() returns multiple strings. You know where they start and end since you know how long they are. When sending the length of your string, make you you use a fixed number of bytes so you can distinguish the string lenght from the string in the byte stream. You will find struct module useful.

How to change email flag to Recent using IMAPClient

I am retrieving emails from my email server using IMAPClient (Python), by checking for emails flagged with "\Recent". After the email has been read the email server automatically sets the email flag to "\Seen".
What I want to do is reset the email flag to "\Recent" so when I check the email directly on the server is still appears as unread.
What I'm finding is that IMAPClient is throwing an exception when I try to add the "\Recent" flag to an email using IMAPClient's "set_flag" definition. Adding any other flag works fine.
The IMAPClient documentation say's the Recent flag is read-only, but I was wondering if there is still a way to mark an email as un-read.
From my understanding email software like Thunderbird allows you to set emails as un-read so I assume there must be a way to do it.
Thanks.
For completeness, here's an actual example using IMAPClient. The \Seen flag is updated in order to control whether messages are marked as read or unread.
from imapclient import IMAPClient, SEEN
client = IMAPClient(...)
client.select_folder('INBOX')
msg_ids = client.search(...)
# Mark messages as read
client.add_flags(msg_ids, [SEEN])
# Mark messages as unread
client.remove_flags(msg_ids, [SEEN])
Note that add_flags and remove_flags are used instead of set_flags because the latter resets the flags to just those specified. When setting the read/unread status you typically want to leave any other message flags intact.
It's also worth noting that it's possible call fetch using the "BODY.PEEK" data item to retrieve parts of messages without affecting the \Seen flag. This can avoid the need to fix up the \Seen flag after downloading a message.
See section 6.4.5 of RFC 3501 for more details.
IMAPClient docs specifically stated the '\Recent' flag is ReadOnly:
http://imapclient.readthedocs.org/en/latest/#message-flags
This is probably a feature (or limitation) of IMAP and IMAP servers. (That is: probably not an IMAPClient limitation).
Use the '\Seen' flag to mark something unread.
Disclaimer: I'm familiar with IMAP but not Python-IMAPClient specifically.
Normally the 'seen' flag determines if an email summary will be shown normal or bold.
You should be able to reset the seen flag. However the recent flag may not be under your direct control. The imap server will set it if notices new messages arriving.
#Menno Smits:
I'm having issues adding the '\Seen' flag to a mail after parsing through it.
I only want to mark a mail as READ when it contains a particular text.
I've been trying to use the add_flags using the "client.add_flags(msg_ids, [SEEN])" you gave above but I keep getting store failed: Command received in invalid state What exactly goes into the [SEEN](is this just a placeholder or the exact syntax?)
Here is a portion of my code:
#login and authentication
context=ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
iobj=imapclient.IMAPClient('outlook.office365.com', ssl=True,ssl_context=context)
iobj.login(uname,pwd)
iobj.select_folder('INBOX', readonly=True)
unread=iobj.search('UNSEEN')
print('There are: ',len(unread),' UNREAD emails')
for i in unread:
mail=iobj.fetch(i,['BODY[]'])
mail_body=html2text.html2text(mcontent.html_part.get_payload().decode(mcontent.html_part.charset))
##Do some regex to parse the email to check if it contains text
meter_no=(re.findall(r'\nACCOUNT NUMBER: (\d+)', mail_body))
req_type=(re.findall(r'Complaint:..+?\n(.+)\n', mail_body))
if 'Key Change' in req_type:
if meter_no in kct['Account_no'].values:
print 'Going to sendmail'# Call a function
sending_email(meter_no,subject,phone_no,req_type,)
mail[b'FLAGS']=r'b\Seen'+','+''+r'b\Answered'##Trying to manuaally alter the flag but didn't work##
iobj.add_flags(i,br'\Seen')# Didn't work too (but is 'i' my msg_id??)
iobj.add_flags(i,[SEEN]) # Complains Name SEEN not defined
else: print 'KCT is yet to be generated'

Categories

Resources