How to pass a variable from one function to another function - python

I am making python based Email broadcasting in which i have created entries like email, pass, there is csv browse as well which will brose a Email_list_container file and a submit button which will call a send mail function to send bulk email along with attachment, problem is when browse is used to grab emails from csv it stores to a variable and then return to function but when I call this variable in send mail function is does not allow me to use it there. same with attachment function is is not coming in send mail function either.
i have tried Global
newvar = browse()
and calling new var but this calls whole function to pop-up again new window to open another file which does not make any sense.
help me guys.
from tkinter import *
import tkinter.messagebox as msg
import smtplib as smtp
import csv
from itertools import chain
#browse function which stores value from csv file
def browse():
from itertools import chain
file_path=filedialog.askopenfilename(title="Open CSV file")
with open(file_path) as csvfile:
read = csv.reader(csvfile)
for row in read:
ini_list.append(row)
flatten_list = list(chain.from_iterable(ini_list))
rcvr_emails =list(flatten_list)
# print(rcvr_emails)
file_label = Label(window,text=file_path, border=0, bg='#BAE1E3',font="inter 10", fg="grey").place(x=330,y=230)
recemail = rcvr_emails
#what i want is submit function to grab a variable from browse function as email list
def submit():
try:
email = login_email.get()
pass_word = login_pass.get()
subject = email_subject.get()
body = email_body.get()
server = smtp.SMTP("smtp.gmail.com",587)
server.starttls()
server.ehlo()
server.login(email,pass_word)
massage = "subject:{}\n\n{}".format(subject,body)
server.sendmail(email,recemail,massage)
server.quit()
msg.showinfo("Status","Mails have been sent to the Targatted Email's List.\nThank You for using our services.")
except:
msg.showwarning("ERROR","SMTP API could not login the credentials,\nPlease check Email & Password then try again.")

Just return recemail from browse function then pass it as argument to submit function:
def browse():
from itertools import chain
file_path=filedialog.askopenfilename(title="Open CSV file")
with open(file_path) as csvfile:
read = csv.reader(csvfile)
for row in read:
ini_list.append(row)
flatten_list = list(chain.from_iterable(ini_list))
rcvr_emails =list(flatten_list)
# print(rcvr_emails)
file_label = Label(window,text=file_path, border=0, bg='#BAE1E3',font="inter 10", fg="grey").place(x=330,y=230)
recemail = rcvr_emails
return recemail
def submit(email_list):
// your code
Then in your main program:
received_email = browse()
submit(received_email)
Or in one line:
submit(browse())

Related

Python-based automation of Outlook using data from an Excel file for the mail body and adding a signature

I'm trying to write a Python script code wherein I’ll send email notifications to my team members on a daily basis.
There are two excel sheets, let's say abc.xlsx and def.xlsx.
I already have a script that updates these files and saves them. (These files abc and def are deleted and recreated with the same name but with updated information.)
Now my goal is to attach the file abc as an attachment in the mail and add the contents of def.xlsx in the email body.
I’m trying to achieve this:
Hello All,
Please find the pending lists here as follows:
///The info from def.xlsx sheet comes here///
Thanks and regards!
/// my outlook signature///
Here is my code:
import win32com.client as win32
import pandas as pd
# reading a file, which needs to be on mail body
df1 = pd.read_excel('def.xlsx')
html_table = df1.to_html(index=False)
outlook = win32.gencache.EnsureDispatch('Outlook.Application')
mail = outlook.CreateItem(0)
mail.To = 'mail#me.com'
mail.CC = 'mail#me.com'
mail.Subject = 'Test mail'
# path to signature should be User\AppData\Roaming\Microsoft\Signatures\signature.htm
pathToIMage = r'path_to_my_signature'
attachment = mail.Attachments.Add(pathToIMage)
attachment.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x3712001F", "MyId1")
# modify the mail body as per need
mail.Attachments.Add(Source="C:\..abc.xlsx")
body = "<p>Hi All, Please find the updates pending updates below:" + html_table + " <br>Thanks and regards <p> <figure><img src=""cid:MyId1""</figure>"
mail.HTMLBody = (body)
mail.Send()
Example:
This type of output I'm expecting
Challenges:
My signature will be a corrupted image with a "x" in it in the test email.
My Excel sheet, which has to be on the body, won't have the same format.
I’ve copied all the codes from Stack overflow only. I did some of my research, but I'm not getting the expected output.
First, you may try setting the BodyFormat property before setting up the HTMLBody property.
Second, to get the signature added to the message body you need to call the Display method before setting up the HTMLBody property.
Third, the <figure> element is not supported in Outlook because Word is used as an email editor and applies its own business rules to message bodies.
Fourth, the HTMLBody property returns or sets a string which represents the message body, it is expected to get or set a full-fledged well-formed HTML document. Try to set up a well-formed HTML document and then set up a property.
If you need to preserve formatting from Excel you may copy the table to the clipboard and then paste it using the Word object model.
Be aware, The Outlook object model supports three main ways of customizing the message body:
The Body property returns or sets a string representing the clear-text body of the Outlook item.
The HTMLBody property of the MailItem class returns or sets a string representing the HTML body of the specified item. Setting the HTMLBody property will always update the Body property immediately. For example:
Sub CreateHTMLMail()
'Creates a new e-mail item and modifies its properties.
Dim objMail As Outlook.MailItem
'Create e-mail item
Set objMail = Application.CreateItem(olMailItem)
With objMail
'Set body format to HTML
.BodyFormat = olFormatHTML
.HTMLBody = "<HTML><BODY>Enter the message text here. </BODY></HTML>"
.Display
End With
End Sub
The Word object model can be used for dealing with message bodies. See Chapter 17: Working with Item Bodies for more information.
Note, the MailItem.BodyFormat property allows you to programmatically change the editor that is used for the body of an item.
I modified it. I'm still working on Challenge 2. I'll just go through the documentation that has been recommended and will share my final script.
import win32com.client as win32
import pandas as pd
import os
import codecs
df1 = pd.read_excel('mail_body.xlsx')
html_table = df1.to_html(index=False)
# below is the coding logic for signature
sig_files_path = 'AppData\Roaming\Microsoft\Signatures\\' + 'signature_file_name' + '_files\\'
sig_html_path = 'AppData\Roaming\Microsoft\Signatures\\' + 'signature_file_name' + '.htm'
signature_path = os.path.join((os.environ['USERPROFILE']), sig_files_path)
html_doc = os.path.join((os.environ['USERPROFILE']), sig_html_path)
html_doc = html_doc.replace('\\\\', '\\')
html_file = codecs.open(html_doc, 'r', 'utf-8', errors='ignore')
signature_code = html_file.read()
signature_code = signature_code.replace(('signature_file_name' + '_files/'), signature_path)
html_file.close()
outlook = win32.gencache.EnsureDispatch('Outlook.Application')
mail = outlook.CreateItem(0)
mail.To = 'mail#me.com'
mail.CC = 'mail#me.com'
mail.Subject = 'TEST EMAIL'
mail.Attachments.Add(Source=r"C:\..abc.xlsx")
# modify the mail body as per need
mail.BodyFormat = 2
body = "<p>Hi All, Please find the updates pending updates below:" + html_table + " <br>Thanks and regards <br><br>"
mail.Display()
mail.HTMLBody = body + signature_code
mail.Send()

Using Variables from Imported files in Python

I am trying to get a variable and its value from another python file that has been Imported . I have the file Main.py and Write.py .In the Main file I am trying to get the variable user_id to equal the new_id variable from the Imported file Write.py .The new_id is creating a hash for the new user when they scan their tag (rfid). The issue is after the tag is scanned the Variable user_id still remains empty. I think I might be grabbing the variable before the tag is scanned, any thoughts? I have posted the code below along with some comments.
from tkinter import *
#Second File
import Write
from tkcalendar import DateEntry
from firebase import firebase
data = {}
global user_id
# Firebase
firebase= firebase.FirebaseApplication("https://xxxxxxx.firebaseio.com/",None)
# button click
def sub ():
global user_id
#setting Variables from user input
name = entry_1.get()
last = entry_2.get()
number = phone.get()
# issue is here
try:
#Calling Function from other file
Write.scan()
if Write.scan():
#getting the New User Id
user_id= new_id
#User Info being sent to the Database
data = {
'Name #': name,
'Last': last,
'Number': number,
'Card #':user_id
}
results = firebase.post('xxxxxxxx/User',data)
except Exception as e:
print(e)
Write.py
import string
from random import*
import RPi.GPIO as GPIO
from mfrc522 import SimpleMFRC522
reader = SimpleMFRC522()
#Function being called
def scan():
try:
#Creating user hash
c = string.digits + string.ascii_letters
new_id = "".join(choice(c) for x in range(randint(25,25)))
print("Please Scan tag")
#Writing to tag
reader.write(new_id)
if reader.write(new_id):
print("Tag Scanned")
else:
print("Scan Tag First")
print("Scanning Complete")
finally:
GPIO.cleanup()
Not sure if this is the actual issue or just the formatting in here, but your indentations for the try: statement are wrong in your main file.

Getting file input into Python script for praw script

So I have a simple reddit bot set up which I wrote using the praw framework. The code is as follows:
import praw
import time
import numpy
import pickle
r = praw.Reddit(user_agent = "Gets the Daily General Thread from subreddit.")
print("Logging in...")
r.login()
words_to_match = ['sdfghm']
cache = []
def run_bot():
print("Grabbing subreddit...")
subreddit = r.get_subreddit("test")
print("Grabbing thread titles...")
threads = subreddit.get_hot(limit=10)
for submission in threads:
thread_title = submission.title.lower()
isMatch = any(string in thread_title for string in words_to_match)
if submission.id not in cache and isMatch:
print("Match found! Thread ID is " + submission.id)
r.send_message('FlameDraBot', 'DGT has been posted!', 'You are awesome!')
print("Message sent!")
cache.append(submission.id)
print("Comment loop finished. Restarting...")
# Run the script
while True:
run_bot()
time.sleep(20)
I want to create a file (text file or xml, or something else) using which the user can change the fields for the various information being queried. For example I want a file with lines such as :
Words to Search for = sdfghm
Subreddit to Search in = text
Send message to = FlameDraBot
I want the info to be input from fields, so that it takes the value after Words to Search for = instead of the whole line. After the information has been input into the file and it has been saved. I want my script to pull the information from the file, store it in a variable, and use that variable in the appropriate functions, such as:
words_to_match = ['sdfghm']
subreddit = r.get_subreddit("test")
r.send_message('FlameDraBot'....
So basically like a config file for the script. How do I go about making it so that my script can take input from a .txt or another appropriate file and implement it into my code?
Yes, that's just a plain old Python config, which you can implement in an ASCII file, or else YAML or JSON.
Create a subdirectory ./config, put your settings in ./config/__init__.py
Then import config.
Using PEP-18 compliant names, the file ./config/__init__.py would look like:
search_string = ['sdfghm']
subreddit_to_search = 'text'
notify = ['FlameDraBot']
If you want more complicated config, just read the many other posts on that.

Calling variables from inside functions in Python

I know I have already asked a question like this before but I have made my code much cleaner and I am still coming up with a problem.
My code goes like this:
class Email_Stuff:
def Get_From_Email():
#code to open up window and get email address
emailaddr = #the input
return emailaddr
def Get_To_Email():
#code to open up window and get to email address
recipaddr = #the input
return recipaddr
def Get_Email_Address():
#code to open up window and get email username
EmailUser = #the input
return EmailUser
def Get_Email_Password():
#code to open up window and get email password
EmailPass = #the input
return EmailPass
def Send_Email():
import smtplib
server = smtplib.SMTP('smtp.gmail.com', 587)
server.login((EmailUser),(EmailPass))
message = "Python Test Email"
server.sendmail(emailaddr,recipaddr,message)
I need to get the variables: emailaddr, recipaddr, EmailUser, and EmailPass into the function Send_Email. I'm not sure how I could do that though because when I run this code, it tells me that "the global name isn't defined".
Any ideas?
Make emailaddr, recipaddr, EmailUser, and EmailPass become instance variables by adding prefix "self.".
class Email_Stuff():
def Get_From_Email(self):
#code to open up window and get email address
self.emailaddr = #the input
def Get_To_Email(self):
#code to open up window and get to email address
self.recipaddr = #the input
def Get_Email_Address(self):
#code to open up window and get email username
self.EmailUser = #the input
def Get_Email_Password(self):
#code to open up window and get email password
self.EmailPass = #the input
def Send_Email(self):
import smtplib
server = smtplib.SMTP('smtp.gmail.com', 587)
server.login((self.EmailUser),(self.EmailPass))
message = "Python Test Email"
server.sendmail(self.emailaddr,self.recipaddr,self.message)
instance = Email_Stuff()
instance.Get_From_Email()
instance.Get_To_Email()
instance.Get_Email_Address()
instance.Get_Email_Password()
instance.Send_Email()
BTW, name of methods should be lowercase.
First, if you want these functions to methods associated with an instance of this class, then each method will need a reference to the instance itself as the first argument, usually designated as self, though you can name it anything you like.
For example:
def Get_Email_Password(self):
#code to open up window and get email password
EmailPass = #the input
return EmailPass
Next, you have two options to get the values ready for sendmail. You can either call each method from within the Send_Email method and store the returned values for each one. That would look like this:
def Send_Email(self):
emailaddr = self.Get_For_Email()
recipaddr = self.Get_Email_Address()
...
Or you can store the values, instead of returning them, as instance variables. So, you would have something like this:
def Get_Email_Password(self):
#code to open up window and get email password
EmailPass = #the input
self.emailaddr = EmailPass
And then, in your Send_Email method, you would reference the instance variables you have saved:
def Send_Email(self):
...
server.sendmail(self.emailaddr, self.recipaddr, self.message)
How you choose to do it is up to you, but I prefer the first way. I also suggest you read up on PEP8

Drop Down Menu In Python calling information from files

So I need a drop down menu, where the user picks his/her client, and it returns information about that client.
lets say i have a file:
["client1", "client2", "client3"]
and I have this code:
from tkinter import *
master = Tk()
with open('ubclientlistvars.txt', 'r') as clients:
clients = (clients.readlines())
variable = StringVar(master)
variable.set("Choose Client")
w = OptionMenu(master, variable, clients)
w.pack()
mainloop()
how would I draw the clients from the file into the drop down menu?
When I run this code, i get these two options:
Choose Client and {["client1", "client2", "client3"]}
You need to actually parse that file. If the file contents are what you posted, then readlines() is just returning a single line of text. It does not magically convert the file contents into a Python object. Suppose the file was:
client1
client2
client3
Then you could use something like clients = [i.strip() for i in f.readlines()] to get a proper list of clients and can pass them to OptionMenu:
w = OptionMenu(master, variable, *clients)
If you cannot change the file format then you will need to clean up the input before displaying it...
import re
data = f.read() # ["client1", "client2", "client3"]
data = re.sub('["\[\]]', '', data) # remove the ", [, and ] characters
clients = data.split(',') # split the list of clients on the comma

Categories

Resources