Skip to content

Commit 8116ce1

Browse files
committed
Update:v1.1.0 - Added Bulk Email Checking
1 parent 80a8f29 commit 8116ce1

3 files changed

Lines changed: 160 additions & 8 deletions

File tree

7.63 KB
Binary file not shown.

src/gui.py

Lines changed: 124 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,69 @@
11
import os
2-
from PyQt5 import QtWidgets, QtCore
3-
from lib.validators import is_valid_email_syntax, has_mx_record, verify_email_smtp
42
import 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

668
class 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')

src/styles.qss

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ QLineEdit {
8383
#supportLabel {
8484
color: #7f8c8d;
8585
font-size: 13px;
86-
margin: 30px 0 15px 0;
86+
margin: 10px 0 15px 0;
8787
text-align: center;
8888
}
8989

@@ -138,4 +138,39 @@ QMessageBox QLabel#qt_msgboxex_icon_label {
138138
/* Force text color for all push buttons */
139139
QPushButton {
140140
color: white;
141+
}
142+
143+
/* Bulk Verify Button */
144+
#bulkButton {
145+
background-color: #9b59b6;
146+
color: white;
147+
padding: 12px 30px;
148+
border: none;
149+
border-radius: 6px;
150+
font-size: 14px;
151+
font-weight: bold;
152+
min-width: 120px;
153+
margin-top: 10px;
154+
}
155+
156+
#bulkButton:hover {
157+
background-color: #8e44ad;
158+
}
159+
160+
/* Results Table */
161+
QTableWidget {
162+
background-color: #ffffff;
163+
border: 1px solid #bdc3c7;
164+
alternate-background-color: #f8f9fa;
165+
}
166+
167+
QHeaderView::section {
168+
background-color: #3498db;
169+
color: white;
170+
padding: 8px;
171+
border: none;
172+
}
173+
174+
QTableWidget::item {
175+
padding: 8px;
141176
}

0 commit comments

Comments
 (0)