Hi
I'm sitting on the proverbial million lines of nasty VB6 code that does actually do what someone wants, but not badly enough to recode it. Now they want to send email via office 365, which requires TLS. VB6 can't do this natively, so I'm trying to launch a python script from VB6, and I think I'm pretty close, but it's not working. It feels like python has the wrong path, and I'm not sure how to fix that.
What I have tried:
First off, here's the code to check that python is installed. This works.
Private Sub Test_Python(Success As Boolean)
On Error GoTo Error_Hand
Dim LogFileHandle As Integer
Dim LogFileName As String
Dim LogDateTime As String
Dim LogFileText As String
Dim PythonCommand As String
Success = False
LogFileName = App.Path & "\Python.log"
LogDateTime = CStr(Now())
PythonCommand = "python.exe -c " & Chr$(34) _
& "import logging; " _
& "logger = logging.getLogger(); " _
& "logging.basicConfig(filename=r'" & LogFileName & "', format='%(message)s', filemode='w'); " _
& "logging.warning('" & LogDateTime & "'); " _
& "raise SystemExit(0)" _
& Chr$(34)
Call ExecCmd(vbNullString, PythonCommand, vbMinimizedNoFocus)
If gblnError_Occured Then
lblX(0).Caption = "ExecCmd [" & glngError_Number & "] " & gstrError_Description
Exit Sub
End If
LogFileHandle = FreeFile()
Open LogFileName For Input As LogFileHandle
Input #LogFileHandle, LogFileText
Close #LogFileHandle
If LogFileText = LogDateTime Then
Success = True
End If
Exit Sub
Error_Hand:
lblX(0).Caption = "Test_Python [" & Err.Number & "] " & Err.Description
End Sub
ExecCmd is a fairly generic function running CreateProcessA, WaitForSingleObject, GetExitCodeProcess, CloseHandle.
Note that this works because my entire python script is in one line, run using the -c switch.
Here's my actual code.
Private Sub Email_Python()
On Error GoTo Error_Hand
Dim LogWasWritten As Boolean
Dim LogError As Boolean
Dim LogFileHandle As Integer
Dim LogFileName As String
Dim LogDateTime As String
Dim LogFileText As String
Dim PythonFileHandle As Integer
Dim PythonFileName As String
Dim PythonScript As String
Dim PythonCommand As String
PythonFileName = "3mail.py"
LogFileName = App.Path & "\Python.log"
LogDateTime = CStr(Now())
LogFileHandle = FreeFile()
Open LogFileName For Output As LogFileHandle
Close #LogFileHandle
PythonCommand = "python.exe " & PythonFileName & " '" & gstrSMTPWord & "' '" & mstrRecipient & "' '" & mstrSubject & "' '" & mstrAttach & "' '" & mstrMessage & "'"
PythonScript = "import logging" _
& vbNewLine & "import os" _
& vbNewLine & "import smtplib" _
& vbNewLine & "import ssl" _
& vbNewLine & "from sys import argv" _
& vbNewLine & "from email import encoders" _
& vbNewLine & "from email.mime.base import MIMEBase" _
& vbNewLine & "from email.mime.multipart import MIMEMultipart" _
& vbNewLine & "from email.mime.text import MIMEText" _
& vbNewLine _
& vbNewLine & "smtp_mailserver = '" & gstrSMTPServer & "'" _
& vbNewLine & "smtp_port = " & CStr(gintSMTPPort) _
& vbNewLine & "from_email = '" & gstrSMTPUser & "'" _
& vbNewLine _
& vbNewLine & "script, from_word, to_email, to_subject, file_name, text_part = argv" _
& vbNewLine _
& vbNewLine & "logger = logging.getLogger()" _
& vbNewLine & "logging.basicConfig(filename=r'" & LogFileName & "', format='%(message)s')" _
& vbNewLine & "logging.warning('DEBUG Start')" _
& vbNewLine & "#DEBUG " & PythonCommand _
& vbNewLine
PythonScript = PythonScript _
& vbNewLine & "message = MIMEMultipart()" _
& vbNewLine & "message['From'] = from_email" _
& vbNewLine & "message['To'] = to_email" _
& vbNewLine & "message['Subject'] = to_subject" _
& vbNewLine & "message.attach(MIMEText(text_part, 'plain'))" _
& vbNewLine
If Not Len(mstrAttach) = 0 Then
If FileExists(mstrAttach) Then
PythonScript = PythonScript _
& vbNewLine & "logging.warning('DEBUG Attachment')" _
& vbNewLine _
& vbNewLine & "try:" _
& vbNewLine & " attachment = open(file_name, 'rb')" _
& vbNewLine & " file_part = MIMEBase('application', 'octet-stream')" _
& vbNewLine & " file_part.set_payload(attachment.read())" _
& vbNewLine & " encoders.encode_base64(file_part)" _
& vbNewLine & " file_part.add_header('Content-Disposition', 'attachment; filename=' + os.path.basename(file_name),)" _
& vbNewLine & " message.attach(file_part)" _
& vbNewLine & "except Exception as e:" _
& vbNewLine & " logging.error(e)" _
& vbNewLine & "finally:" _
& vbNewLine & " attachment.close()" _
& vbNewLine
End If
End If
PythonScript = PythonScript _
& vbNewLine & "to_message = message.as_string()" _
& vbNewLine _
& vbNewLine & "logging.warning('DEBUG Send')" _
& vbNewLine _
& vbNewLine & "try:"
If gblnSMTP_TLS Then
PythonScript = PythonScript _
& vbNewLine & " Security_context = ssl.create_default_context()" _
& vbNewLine & " mailserver = smtplib.SMTP(smtp_mailserver,smtp_port)" _
& vbNewLine & " mailserver.starttls(context=Security_context)"
Else
PythonScript = PythonScript _
& vbNewLine & " mailserver = smtplib.SMTP(smtp_mailserver,smtp_port)"
End If
PythonScript = PythonScript _
& vbNewLine & " mailserver.login(from_email, from_word)" _
& vbNewLine & " mailserver.sendmail(from_email, to_email, to_message)" _
& vbNewLine & "except Exception as e:" _
& vbNewLine & " logging.error(e)" _
& vbNewLine & "finally:" _
& vbNewLine & " mailserver.close()" _
& vbNewLine
PythonScript = PythonScript _
& vbNewLine & "logging.warning('" & LogDateTime & "')" _
& vbNewLine & "raise SystemExit(0) "
PythonFileHandle = FreeFile()
Open App.Path & "\" & PythonFileName For Output As PythonFileHandle
Print #PythonFileHandle, PythonScript
Close #PythonFileHandle
PythonScript = ""
Call ExecCmd(App.Path & "\", PythonCommand, vbMinimizedNoFocus)
If gblnError_Occured Then
lblX(0).Caption = "ExecCmd [" & glngError_Number & "] " & gstrError_Description
Exit Sub
End If
PythonCommand = ""
LogFileHandle = FreeFile()
Open LogFileName For Input As LogFileHandle
LogWasWritten = False
LogError = False
lblX(0).Caption = LogDateTime & "|"
Do While Not EOF(LogFileHandle)
Input #LogFileHandle, LogFileText
If LogFileText = LogDateTime Then
LogWasWritten = True
Exit Do
Else
LogError = True
lblX(0).Caption = lblX(0).Caption & LogFileText & vbNewLine
End If
Loop
Close #LogFileHandle
If LogWasWritten Then
If LogError = False Then
SaveSetting ...
End If
End If
Exit Sub
Error_Hand:
lblX(0).Caption = "Python [" & Err.Number & "] " & Err.Description
End Sub
Now if I run this, Python.log remains zero length. However, if I then execute the 3mail.py script, using the PythonCommand DEBUG settings I wrote into the script, it .. gives a stack of useful errors I can fix later. For now, I want the script to run when called from VB. Any ideas? Yes, not that idea, I already said I'm stuck with VB :p