Building a Desktop SMTP Email Sender with Java Swing

Sending emails programmatically is a common requirement for many desktop applications, from newsletter tools to automated notification systems. While Java provides the robust javax.mail API (now Jakarta Mail) for handling email protocols, combining it with a Swing GUI creates a user-friendly desktop utility.

This article guides you through building a fully-featured SMTP email client with a graphical user interface in Java, supporting attachments, HTML content, and secure authentication.


Architecture and Technologies

Our application will be built on two main pillars:

  1. Frontend (GUI): Java Swing for the user interface.
  2. Backend (Email): Jakarta Mail (formerly JavaMail) for SMTP communication.

Project Setup: Dependencies

You need to add the Jakarta Mail dependency to your project.

Maven:

<dependencies>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>jakarta.mail</artifactId>
<version>2.0.1</version>
</dependency>
<!-- Also ensure you have the Jakarta Activation API -->
<dependency>
<groupId>com.sun.activation</groupId>
<artifactId>jakarta.activation</artifactId>
<version>2.0.1</version>
</dependency>
</dependencies>

Gradle:

dependencies {
implementation 'com.sun.mail:jakarta.mail:2.0.1'
implementation 'com.sun.activation:jakarta.activation:2.0.1'
}

Building the GUI: A Step-by-Step Approach

We'll create a form with fields for all essential email components and a console for feedback.

Main Application Frame

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.File;
public class EmailSenderGUI extends JFrame {
// Form components
private JTextField smtpHostField, smtpPortField, usernameField;
private JPasswordField passwordField;
private JCheckBox authCheckBox, tlsCheckBox;
private JTextField toField, ccField, bccField, subjectField;
private JTextArea messageArea;
private JButton attachButton, sendButton, clearButton;
private JList<File> attachmentList;
private DefaultListModel<File> attachmentListModel;
private JTextArea consoleArea;
public EmailSenderGUI() {
initializeGUI();
}
private void initializeGUI() {
setTitle("Java SMTP Email Sender");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout(10, 10));
// Create main panels
JPanel serverPanel = createServerPanel();
JPanel recipientPanel = createRecipientPanel();
JPanel messagePanel = createMessagePanel();
JPanel attachmentPanel = createAttachmentPanel();
JPanel buttonPanel = createButtonPanel();
JPanel consolePanel = createConsolePanel();
// Arrange panels in the frame
JPanel northPanel = new JPanel(new GridLayout(3, 1, 5, 5));
northPanel.add(serverPanel);
northPanel.add(recipientPanel);
northPanel.add(attachmentPanel);
add(northPanel, BorderLayout.NORTH);
add(messagePanel, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.SOUTH);
add(consolePanel, BorderLayout.SOUTH);
// Adjust layout
pack();
setSize(800, 700);
setLocationRelativeTo(null); // Center the window
}

Server Configuration Panel

    private JPanel createServerPanel() {
JPanel panel = new JPanel(new GridLayout(0, 2, 5, 5));
panel.setBorder(BorderFactory.createTitledBorder("SMTP Server Configuration"));
// Initialize components
smtpHostField = new JTextField("smtp.gmail.com");
smtpPortField = new JTextField("587");
usernameField = new JTextField();
passwordField = new JPasswordField();
authCheckBox = new JCheckBox("Require Authentication", true);
tlsCheckBox = new JCheckBox("Use STARTTLS", true);
// Add components to panel
panel.add(new JLabel("SMTP Host:"));
panel.add(smtpHostField);
panel.add(new JLabel("SMTP Port:"));
panel.add(smtpPortField);
panel.add(new JLabel("Username:"));
panel.add(usernameField);
panel.add(new JLabel("Password:"));
panel.add(passwordField);
panel.add(authCheckBox);
panel.add(tlsCheckBox);
return panel;
}

Recipient Information Panel

    private JPanel createRecipientPanel() {
JPanel panel = new JPanel(new GridLayout(0, 2, 5, 5));
panel.setBorder(BorderFactory.createTitledBorder("Recipients"));
toField = new JTextField();
ccField = new JTextField();
bccField = new JTextField();
subjectField = new JTextField();
panel.add(new JLabel("To (comma-separated):"));
panel.add(toField);
panel.add(new JLabel("CC (comma-separated):"));
panel.add(ccField);
panel.add(new JLabel("BCC (comma-separated):"));
panel.add(bccField);
panel.add(new JLabel("Subject:"));
panel.add(subjectField);
return panel;
}

Message Composition Panel

    private JPanel createMessagePanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createTitledBorder("Message"));
messageArea = new JTextArea(15, 50);
messageArea.setLineWrap(true);
messageArea.setWrapStyleWord(true);
JScrollPane scrollPane = new JScrollPane(messageArea);
panel.add(scrollPane, BorderLayout.CENTER);
return panel;
}

Attachment Management Panel

    private JPanel createAttachmentPanel() {
JPanel panel = new JPanel(new BorderLayout(5, 5));
panel.setBorder(BorderFactory.createTitledBorder("Attachments"));
attachmentListModel = new DefaultListModel<>();
attachmentList = new JList<>(attachmentListModel);
JScrollPane listScrollPane = new JScrollPane(attachmentList);
attachButton = new JButton("Add Attachment");
JButton removeButton = new JButton("Remove Selected");
attachButton.addActionListener(this::addAttachment);
removeButton.addActionListener(this::removeAttachment);
JPanel buttonPanel = new JPanel();
buttonPanel.add(attachButton);
buttonPanel.add(removeButton);
panel.add(listScrollPane, BorderLayout.CENTER);
panel.add(buttonPanel, BorderLayout.SOUTH);
return panel;
}
private void addAttachment(ActionEvent e) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setMultiSelectionEnabled(true);
int result = fileChooser.showOpenDialog(this);
if (result == JFileChooser.APPROVE_OPTION) {
File[] files = fileChooser.getSelectedFiles();
for (File file : files) {
if (!attachmentListModel.contains(file)) {
attachmentListModel.addElement(file);
}
}
}
}
private void removeAttachment(ActionEvent e) {
int[] selectedIndices = attachmentList.getSelectedIndices();
for (int i = selectedIndices.length - 1; i >= 0; i--) {
attachmentListModel.remove(selectedIndices[i]);
}
}

Action Buttons and Console

    private JPanel createButtonPanel() {
JPanel panel = new JPanel(new FlowLayout());
sendButton = new JButton("Send Email");
clearButton = new JButton("Clear All");
sendButton.addActionListener(this::sendEmail);
clearButton.addActionListener(this::clearAll);
panel.add(sendButton);
panel.add(clearButton);
return panel;
}
private JPanel createConsolePanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createTitledBorder("Console Output"));
consoleArea = new JTextArea(8, 60);
consoleArea.setEditable(false);
consoleArea.setBackground(Color.BLACK);
consoleArea.setForeground(Color.GREEN);
consoleArea.setFont(new Font("Monospaced", Font.PLAIN, 12));
JScrollPane scrollPane = new JScrollPane(consoleArea);
panel.add(scrollPane, BorderLayout.CENTER);
return panel;
}
private void clearAll(ActionEvent e) {
toField.setText("");
ccField.setText("");
bccField.setText("");
subjectField.setText("");
messageArea.setText("");
attachmentListModel.clear();
consoleArea.setText("");
}
private void log(String message) {
consoleArea.append(message + "\n");
consoleArea.setCaretPosition(consoleArea.getDocument().getLength()); // Auto-scroll
}

The Email Sending Engine

This is the core functionality that uses Jakarta Mail to send emails.

    private void sendEmail(ActionEvent e) {
// Run in a separate thread to keep GUI responsive
SwingWorker<Boolean, String> worker = new SwingWorker<>() {
@Override
protected Boolean doInBackground() throws Exception {
try {
publish("Starting email sending process...");
// Validate required fields
if (toField.getText().trim().isEmpty()) {
publish("ERROR: No recipients specified.");
return false;
}
// Get SMTP properties
java.util.Properties props = new java.util.Properties();
props.put("mail.smtp.auth", String.valueOf(authCheckBox.isSelected()));
props.put("mail.smtp.starttls.enable", String.valueOf(tlsCheckBox.isSelected()));
props.put("mail.smtp.host", smtpHostField.getText());
props.put("mail.smtp.port", smtpPortField.getText());
// For debugging
props.put("mail.debug", "true");
// Get session
jakarta.mail.Session session;
if (authCheckBox.isSelected()) {
session = jakarta.mail.Session.getInstance(props, 
new jakarta.mail.Authenticator() {
@Override
protected jakarta.mail.PasswordAuthentication getPasswordAuthentication() {
return new jakarta.mail.PasswordAuthentication(
usernameField.getText(), 
new String(passwordField.getPassword())
);
}
});
} else {
session = jakarta.mail.Session.getInstance(props);
}
// Create message
jakarta.mail.Message message = new jakarta.mail.internet.MimeMessage(session);
message.setFrom(new jakarta.mail.internet.InternetAddress(usernameField.getText()));
// Set recipients
message.setRecipients(jakarta.mail.Message.RecipientType.TO, 
jakarta.mail.internet.InternetAddress.parse(toField.getText()));
if (!ccField.getText().trim().isEmpty()) {
message.setRecipients(jakarta.mail.Message.RecipientType.CC, 
jakarta.mail.internet.InternetAddress.parse(ccField.getText()));
}
if (!bccField.getText().trim().isEmpty()) {
message.setRecipients(jakarta.mail.Message.RecipientType.BCC, 
jakarta.mail.internet.InternetAddress.parse(bccField.getText()));
}
message.setSubject(subjectField.getText());
// Create multipart message for text and attachments
jakarta.mail.Multipart multipart = new jakarta.mail.internet.MimeMultipart();
// Create text part
jakarta.mail.BodyPart messageBodyPart = new jakarta.mail.internet.MimeBodyPart();
String messageText = messageArea.getText();
// Check if message contains HTML
if (messageText.trim().startsWith("<html>")) {
messageBodyPart.setContent(messageText, "text/html; charset=utf-8");
} else {
messageBodyPart.setText(messageText);
}
multipart.addBodyPart(messageBodyPart);
// Add attachments
for (int i = 0; i < attachmentListModel.size(); i++) {
File file = attachmentListModel.getElementAt(i);
publish("Attaching file: " + file.getName());
messageBodyPart = new jakarta.mail.internet.MimeBodyPart();
messageBodyPart.setDataHandler(
new jakarta.activation.DataHandler(
new jakarta.activation.FileDataSource(file)
)
);
messageBodyPart.setFileName(file.getName());
multipart.addBodyPart(messageBodyPart);
}
// Set the complete message parts
message.setContent(multipart);
// Send message
publish("Sending email...");
jakarta.mail.Transport.send(message);
publish("SUCCESS: Email sent successfully!");
return true;
} catch (Exception ex) {
publish("ERROR: " + ex.getMessage());
ex.printStackTrace();
return false;
}
}
@Override
protected void process(java.util.List<String> chunks) {
for (String message : chunks) {
log(message);
}
}
@Override
protected void done() {
sendButton.setEnabled(true);
try {
Boolean success = get();
if (success) {
JOptionPane.showMessageDialog(EmailSenderGUI.this, 
"Email sent successfully!", "Success", 
JOptionPane.INFORMATION_MESSAGE);
}
} catch (Exception ex) {
log("ERROR in worker thread: " + ex.getMessage());
}
}
};
sendButton.setEnabled(false);
worker.execute();
}

Main Method

    public static void main(String[] args) {
// Set system look and feel
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeel());
} catch (Exception e) {
e.printStackTrace();
}
SwingUtilities.invokeLater(() -> {
new EmailSenderGUI().setVisible(true);
});
}
}

Configuration for Popular Email Providers

Gmail:

  • SMTP Host: smtp.gmail.com
  • Port: 587 (TLS) or 465 (SSL)
  • Requires "App Password" if 2-factor authentication is enabled

Outlook/Office 365:

  • SMTP Host: smtp.office365.com
  • Port: 587
  • Requires authentication

Yahoo Mail:

  • SMTP Host: smtp.mail.yahoo.com
  • Port: 587
  • Requires authentication

Security Considerations

  1. Password Storage: The current implementation stores passwords in memory only during the session. For production applications, consider using secure credential storage.
  2. SSL/TLS: Always use TLS (STARTTLS) for secure communication.
  3. Input Validation: Validate all user inputs to prevent injection attacks.
  4. File Security: Validate attachment types and sizes to prevent security risks.

Conclusion

This SMTP Email Sender GUI provides a solid foundation for a desktop email utility. You can extend it with features like:

  • Email templates
  • Contact list integration
  • Rich text editing for HTML emails
  • Batch sending capabilities
  • SSL certificate handling
  • Logging and sent items history

The combination of Swing for the interface and Jakarta Mail for the email functionality creates a powerful, self-contained application that demonstrates several important Java concepts including GUI development, network communication, and multi-threading with SwingWorker.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper