0

I created my Java App to Send emails from the table and after that to update Sent emails column in the table. What I want now is instead of updating one at the time I would like to update all emails at once. Here is my code Send Emails:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;

import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class TestSendEmails {
    private String RecordId;
    private String emailTo;
    private String emailSubject;
    private String emailBody;
    private String emailAttachments;

    public TestSendEmails(){

    }

    public TestSendEmails(String emailTo, String emailSubject, String emailBody, String emailAttachments, String RecordId){
        super();
        this.emailTo = emailTo;
        this.emailSubject = emailSubject;
        this.emailBody = emailBody;
        this.emailAttachments = emailAttachments;
        this.RecordId = RecordId;
    }

    public String getEmailTo(){
        return emailTo;
    }

    public void setEmailTo(String emailTo){
        this.emailTo = emailTo;
    }

    public String getEmailSubject(){
        return emailSubject;
    }

    public void setEmailSubject(String emailSubject){
        this.emailSubject = emailSubject;
    }

    public String getEmailBody(){
        return emailBody;
    }

    public void setEmailBody(String emailBody){
        this.emailBody = emailBody;
    }

    public String getEmailAttachments(){
        return emailAttachments;
    }

    public void setEmailAttachments(String emailAttachments){
        this.emailAttachments = emailAttachments;
    }

    public String getRecordId(){
        return RecordId;
    }

    public void setRecordId(String RecordId){
        this.RecordId = RecordId;
    }
}

class TestSendEmailD{
    private Connection con;

    private static final String GET_EMAILS = "Select Top 45 * From Email Where SentOn is null Order By RecordId";

    private void connect() throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException{
        Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver").newInstance();

        con = DriverManager.getConnection("jdbc:sqlserver://xxxxxxxxx\\SQLEXPRESS:1000;databaseName=Test;user=xxxx;password=xxxx");
    }

    public List<TestSendEmails> getTestSendEmails() throws Exception{
        connect();
        PreparedStatement ps = con.prepareStatement(GET_EMAILS);

        ResultSet rs = ps.executeQuery();

        List<TestSendEmails> result = new ArrayList<TestSendEmails>();

       int count = 0;
    while(rs.next()){
        result.add(new TestSendEmails(rs.getString("emailTo"), rs.getString("emailSubject"),rs.getString("emailBody"),rs.getString("emailAttachments"),rs.getString("RecordId")));
        count++;
    }
    System.out.println(count);
        disconnect();
        return result;
    }

    private void disconnect() throws SQLException{
        if(con != null){
            con.close();
        }
    }
}

class EmailSender{
    private Session session;

    private void init(){
        Properties props = new Properties();
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.smtp.host", "xxxxxxxxx");
        props.put("mail.smtp.port", "xxxx");

        session = Session.getInstance(props,
                  new javax.mail.Authenticator() {
                    protected PasswordAuthentication getPasswordAuthentication() {

                        return new PasswordAuthentication("test@gmail.com", "xxxxx");
                    }
                  });
    }
    //Creating new connection to Update stpEmailLog table
    public static Connection getConnection() throws Exception {
        String driver = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
        String url = "jdbc:sqlserver://xxxxxxxxx\\:1000;databaseName=Email";
        String username = "xxxx";
        String password = "xxxxx";
        Class.forName(driver);
        Connection conn = DriverManager.getConnection(url, username, password);
        return conn;
      }

    public void sendEmail(TestSendEmails s) throws Exception{
        init();
        Message message = new MimeMessage(session);
        Connection conn = null;
        PreparedStatement pstmt = null;
        conn = getConnection();
        java.util.Date date = new Date();

        message.setFrom(new InternetAddress("test@gmail.com"));

        String query = "update Email set SentOn = ? where RecordId = ? ";
        pstmt = conn.prepareStatement(query); // create a statement

        String str[]=String.valueOf(s.getRecordId()).split(";");//RecordId1;RecordId;RecordId3;.... 

        for(int i=0;i<str.length;i++){
        message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(s.getEmailTo().replace(";", ",")));
        message.setSubject(s.getEmailSubject());
        message.setText(s.getEmailBody());

        message.setContent(s.getEmailBody(),"text/html");
        Transport.send(message);
        System.out.println("Email sent.");

        pstmt.setTimestamp(1, new java.sql.Timestamp(date.getTime()));

        pstmt.setString(2, str[i]); 

        pstmt.executeUpdate(); // Execute Update statement
        }
    }

    public void sendEmail(List<TestSendEmails> emails) throws Exception{
        for(TestSendEmails TestSendEmails:emails ){
            sendEmail(TestSendEmails);
            System.out.println(TestSendEmails);
        }
    }
}

Here is the line of code that I use to update my field in the table:

pstmt.executeUpdate();

I'm not sure if I can just move this to a different place and that way update that filed with all emails instead of updating them one by one. If anyone can help me with this please let me know.

espresso_coffee
  • 5,980
  • 11
  • 83
  • 193
  • Are you asking for a better query to use when creating your prepared statement, or for help refactoring your code to keep track of sent emails so that you CAN write such a query? – Bobby StJacques Aug 10 '15 at 20:51
  • Sounds like you just want to do a standard batch update? Like http://stackoverflow.com/questions/3784197/efficient-way-to-do-batch-inserts-with-jdbc? – BlakeP Aug 10 '15 at 20:54
  • My query works fine, only issue that I have is instead of updating SentOn field in my table one at the time I would like to check first all fileds that should be update and then update them all in once. Now my query running every time for each record. – espresso_coffee Aug 10 '15 at 20:54
  • BlakeP yes that is what I'm looking for in my code. – espresso_coffee Aug 10 '15 at 20:56
  • Does anyone know how I can put number of sent emails in log events text file? – espresso_coffee Aug 11 '15 at 13:30

1 Answers1

1

Should be simple enough to make it run in a batch. In your sendEmail method you should just need to change the pstmt.executeUpdate(); to pstmt.addBatch();, then outside of your for loop, just call pstmt.executeBatch();.

public void sendEmail(TestSendEmails s) throws Exception{
    init();
    Message message = new MimeMessage(session);
    Connection conn = null;
    PreparedStatement pstmt = null;
    conn = getConnection();
    java.util.Date date = new Date();

    message.setFrom(new InternetAddress("test@gmail.com"));

    String query = "update Email set SentOn = ? where RecordId = ? ";
    pstmt = conn.prepareStatement(query); // create a statement

    String str[]=String.valueOf(s.getRecordId()).split(";");//RecordId1;RecordId;RecordId3;....

    for(int i=0;i<str.length;i++){
        message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(s.getEmailTo().replace(";", ",")));
        message.setSubject(s.getEmailSubject());
        message.setText(s.getEmailBody());

        message.setContent(s.getEmailBody(),"text/html");
        Transport.send(message);
        System.out.println("Email sent.");

        pstmt.setTimestamp(1, new java.sql.Timestamp(date.getTime()));

        pstmt.setString(2, str[i]);

        pstmt.addBatch(); // Add to batch
    }

    pstmt.executeBatch(); // Execute batch
}
Andrew Mairose
  • 10,615
  • 12
  • 60
  • 102
  • I have a question about this, what is a difference in this solution with batch and my previous code? I still see after I run my code in eclipse that my code execute emails one at the time. – espresso_coffee Aug 11 '15 at 12:53
  • Instead of doing (send email -> write to database -> send email -> write to database -> send email -> write to database... etc. etc.), doing it with batch will look more like (send email -> add record to batch -> send email -> add record to batch... etc. etc.), then after all the emails are sent, it will execute all of the update statements that are in your batch. – Andrew Mairose Aug 11 '15 at 13:56
  • That is exactly what I need, I tried and works fine. Thanks for help. I have one more question for you. How I can add Log Handler that will write date, time and number of sent emails and handle connection errors? I already have part where I count number of emails but I do not know how to write all of that in text file. – espresso_coffee Aug 11 '15 at 14:03
  • If you want to do it the 'right' way, look into a java logging library like [log4j](http://logging.apache.org/log4j/2.x/). – Andrew Mairose Aug 11 '15 at 14:21