11import os
2- from PyQt5 import QtWidgets , QtCore
3- from lib .validators import is_valid_email_syntax , has_mx_record , verify_email_smtp
42import webbrowser
3+ from PyQt5 import QtWidgets , QtCore , QtGui
4+ from lib .validators import is_valid_email_syntax , has_mx_record , verify_email_smtp
5+ import pandas as pd
6+
7+ class ResultDialog (QtWidgets .QDialog ):
8+ def __init__ (self , parent = None ):
9+ super ().__init__ (parent )
10+ self .setWindowTitle ("KnowEmail - Verifying Bulk Emails" )
11+ self .setMinimumSize (600 , 400 )
12+
13+ self .layout = QtWidgets .QVBoxLayout ()
14+ self .table = QtWidgets .QTableWidget ()
15+ self .table .setColumnCount (2 )
16+ self .table .setHorizontalHeaderLabels (["Email" , "Status" ])
17+ self .table .horizontalHeader ().setStretchLastSection (True )
18+
19+ self .layout .addWidget (self .table )
20+ self .setLayout (self .layout )
21+
22+ def add_row (self , email , status ):
23+ row_position = self .table .rowCount ()
24+ self .table .insertRow (row_position )
25+
26+ email_item = QtWidgets .QTableWidgetItem (email )
27+ status_item = QtWidgets .QTableWidgetItem (status )
28+
29+ if status == "Valid" :
30+ status_item .setForeground (QtGui .QColor ('#27ae60' )) # Green
31+ elif status .startswith ("Invalid" ):
32+ status_item .setForeground (QtGui .QColor ('#e74c3c' )) # Red
33+ else :
34+ status_item .setForeground (QtGui .QColor ('#f1c40f' )) # Yellow
35+
36+ self .table .setItem (row_position , 0 , email_item )
37+ self .table .setItem (row_position , 1 , status_item )
38+
39+ class BulkVerificationThread (QtCore .QThread ):
40+ result_signal = QtCore .pyqtSignal (str , str )
41+ all_done = QtCore .pyqtSignal ()
42+
43+ def __init__ (self , emails ):
44+ super ().__init__ ()
45+ self .emails = emails
46+
47+ def run (self ):
48+ for email in self .emails :
49+ if not email :
50+ continue
51+
52+ try :
53+ if not is_valid_email_syntax (email ):
54+ status = "Invalid (Syntax)"
55+ elif not has_mx_record (email .split ('@' )[1 ]):
56+ status = "Invalid (No MX)"
57+ elif not verify_email_smtp (email ):
58+ status = "Invalid (SMTP)"
59+ else :
60+ status = "Valid"
61+ except Exception as e :
62+ status = f"Error: { str (e )} "
63+
64+ self .result_signal .emit (email , status )
65+
66+ self .all_done .emit () # Signal completion after all emails
567
668class EmailValidatorApp (QtWidgets .QWidget ):
769 def __init__ (self ):
@@ -11,9 +73,10 @@ def __init__(self):
1173 self .verifying_timer = QtCore .QTimer ()
1274 self .verifying_counter = 1
1375 self .verifying_timer .timeout .connect (self .update_verifying_text )
76+ self .verification_thread = None
1477
1578 def init_ui (self ):
16- self .setWindowTitle ("KnowEmail - Email Validator " )
79+ self .setWindowTitle ("KnowEmail" )
1780 self .setMinimumSize (600 , 500 )
1881
1982 # Main layout
@@ -26,15 +89,16 @@ def init_ui(self):
2689 title = QtWidgets .QLabel ("KnowEmail" )
2790 title .setObjectName ("title" )
2891
29- subtitle = QtWidgets .QLabel ("Ad-Free & Open Source" )
92+ subtitle = QtWidgets .QLabel ("Ad-Free & Open Source Bulk Email Verifier " )
3093 subtitle .setObjectName ("subtitle" )
3194
3295 header_layout .addWidget (title , 0 , QtCore .Qt .AlignHCenter )
3396 header_layout .addWidget (subtitle , 0 , QtCore .Qt .AlignHCenter )
3497 main_layout .addLayout (header_layout )
3598
99+ # Description
36100 description = QtWidgets .QLabel (
37- "Tired of dealing with invalid email addresses? KnowEmail helps you "
101+ "Tired of dealing with invalid email addresses? Free Email Verifier tool helps you "
38102 "clean your email lists by ensuring every address is valid before you send that "
39103 "important campaign."
40104 )
@@ -61,11 +125,17 @@ def init_ui(self):
61125 self .result_label .setObjectName ("resultLabel" )
62126 main_layout .addWidget (self .result_label )
63127
128+ # Bulk Verify Button
129+ self .bulk_button = QtWidgets .QPushButton ("Check Multiple Emails" )
130+ self .bulk_button .setObjectName ("bulkButton" )
131+ self .bulk_button .clicked .connect (self .bulk_verify )
132+ main_layout .addWidget (self .bulk_button )
133+
64134 # Support Section
65135 support_layout = QtWidgets .QVBoxLayout ()
66136 support_label = QtWidgets .QLabel (
67- "We've made this tool free and open-source for everyone. If you'd like to support our "
68- "development efforts, consider donating."
137+ "We've made this tool free and open-source for everyone."
138+ "If you'd like to support our development efforts, consider donating."
69139 )
70140 support_label .setWordWrap (True )
71141 support_label .setObjectName ("supportLabel" )
@@ -77,10 +147,57 @@ def init_ui(self):
77147 support_layout .addWidget (support_label , 0 , QtCore .Qt .AlignHCenter )
78148 support_layout .addWidget (donate_button , 0 , QtCore .Qt .AlignHCenter )
79149 main_layout .addLayout (support_layout )
150+
151+ # Add spacer to push support section to bottom
80152 main_layout .addStretch (1 )
81153
82154 self .setLayout (main_layout )
83155
156+ def bulk_verify (self ):
157+ file_dialog = QtWidgets .QFileDialog ()
158+ file_path , _ = file_dialog .getOpenFileName (
159+ self ,
160+ "Select Email List" ,
161+ "" ,
162+ "Text Files (*.txt);;Excel Files (*.xlsx)"
163+ )
164+
165+ if not file_path :
166+ return
167+
168+ try :
169+ if file_path .endswith ('.txt' ):
170+ with open (file_path , 'r' ) as f :
171+ emails = [line .strip () for line in f .readlines () if line .strip ()]
172+ elif file_path .endswith ('.xlsx' ):
173+ df = pd .read_excel (file_path )
174+ emails = df .iloc [:, 0 ].astype (str ).tolist ()
175+ else :
176+ raise ValueError ("Unsupported file format" )
177+ except Exception as e :
178+ QtWidgets .QMessageBox .critical (self , "Error" , f"Failed to read file: { str (e )} " )
179+ return
180+
181+ self .results_dialog = ResultDialog (self )
182+ self .results_dialog .show ()
183+
184+ # Start verification in background
185+ self .verification_thread = BulkVerificationThread (emails )
186+ self .verification_thread .result_signal .connect (self .update_results )
187+ self .verification_thread .all_done .connect (self .show_completion_popup ) # Add this
188+ self .verification_thread .start ()
189+
190+ def show_completion_popup (self ):
191+ QtWidgets .QMessageBox .information (
192+ self ,
193+ "Process Complete" ,
194+ "All emails from the file have been checked!" ,
195+ QtWidgets .QMessageBox .Ok
196+ )
197+
198+ def update_results (self , email , status ):
199+ self .results_dialog .add_row (email , status )
200+
84201 def apply_styles (self ):
85202 current_dir = os .path .dirname (os .path .abspath (__file__ ))
86203 style_path = os .path .join (current_dir , 'styles.qss' )
0 commit comments