使用java 多个邮箱获取认证问题

**使用java 多个邮箱获取认证问题 **

我有一批smtp 账号 想测试获取全部认证 但是发现 传进去之后 调用方法 只有先进去的list的 host 才能认证成功

  • 下方代码 先执行的是smtp.aol.com 地址 所有都能判断认证 都可以成功 但是host地址变了之后 其他的都不能判断

如果把smtp.sina.com 的先放到list里面 新浪的都可以判断 其他的不行
抛的异常是这个 请指点
javax.mail.AuthenticationFailedException: 535 5.7.0 (#AUTH005) Too many bad auth attempts.

package com.itheima.utlis;

import com.itheima.pojo.EmailUser;

import javax.mail.*;
import java.util.ArrayList;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class EmailUtis {

    public static void main(String[] args) {


        ArrayList<EmailUser> emailUsers = new ArrayList<>();

        emailUsers.add(new EmailUser("smtp.aol.com", "thiriot.sharon9986@aol.com", "exhfbwzrqbqjsanq"));
        emailUsers.add(new EmailUser("smtp.aol.com", "thiriot.sharon9986@aol.com", "exhfbwzrqbqjsanq"));

       emailUsers.add(new EmailUser("smtp.sina.com", "gmywgw@sina.com", "0913ca85741ebe91"));
        emailUsers.add(new EmailUser("smtp.sina.com", "gmywgw@sina.com", "0913ca85741ebe91"));






        ExecutorService executor = Executors.newFixedThreadPool(10); // 10 threads in pool

        for (EmailUser emailUser : emailUsers) {
            checkEmail(emailUser.getHost(), emailUser.getEmail(), emailUser.getPassword());


        }

    

    }

    /**
     * @param host     SMTP服务端地址,如qq邮箱为smtp.qq.com
     * @param email    邮箱名
     * @param password 邮箱注册码(非登录名,具体需根据邮箱到官网申请)
     * @return 如果可用返回true
     * @throws MessagingException
     */
    public static Object checkEmail(String host, String email, String password) {
        Properties props = new Properties();

        props.put("mail.transport.protocol", "smtp");// 连接协议
        props.put("mail.smtp.host", host);// 主机名,必须要,也可以使用smtp.sina.com.cn
        //   props.put("mail.smtp.port", 465);// 端口号,写不写无所谓,不确定的情况下,可以不写
        props.put("mail.smtp.auth", "true");// 是否鉴权,必须要
        props.put("mail.smtp.ssl.enable", "true");// 设置是否使用ssl安全连接,一般都使用
        props.put("mail.smtp.starttls.enable", "true");

        Session session = Session.getDefaultInstance(props);
        // session.setDebug(true);

        Transport transport = null;
        try {
            transport = session.getTransport();
        } catch (NoSuchProviderException e) {
            e.printStackTrace();
        }


        try {
            //    System.out.println(email + "--" + password);
            transport.connect(email, password);
            System.out.println(email + "认证成功"+session.toString());

            return true;
        } catch (MessagingException e) {
              e.printStackTrace();
            System.out.println(email + "认证失败"+session.toString());
            return false;
        }finally {
            if (transport != null) {
                try {
                    transport.close();
                    props.clone();
                } catch (MessagingException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}


根据你提供的代码,存在以下问题:

1、你创建了一个线程池(ExecutorService),但没有将任务提交给线程池执行,而是直接在主线程中调用checkEmail方法。这样做并不会利用线程池的并发执行能力。你可以使用线程池的submit方法将任务提交给线程池执行。

2、你的异常信息显示为javax.mail.AuthenticationFailedException: 535 5.7.0 (#AUTH005) Too many bad auth attempts.,这意味着认证失败次数过多。可能原因是你频繁地使用相同的账号和密码进行认证,导致邮件服务提供商限制了你的访问。你可以尝试增加认证间隔时间或者使用不同的邮箱账号进行测试,以避免频繁认证的限制。

3、在循环中,你创建了多个Session对象,并将其传递给checkEmail方法。这样做并不会提高性能,因为在每次循环中都会重新创建一个Session对象。建议在循环外部创建一个Session对象,并将其传递给checkEmail方法。

4、在finally块中,你使用了props.clone()来复制Properties对象,但是这并不是复制对象的正确方式。clone()方法是浅拷贝,只会复制对象的引用,不会复制对象的内容。你可以直接创建一个新的Properties对象来替代原来的对象。

根据上述建议,你可以尝试修改代码如下:

import com.itheima.pojo.EmailUser;

import javax.mail.*;
import java.util.ArrayList;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class EmailUtis {

    public static void main(String[] args) {
        ArrayList<EmailUser> emailUsers = new ArrayList<>();
        emailUsers.add(new EmailUser("smtp.aol.com", "thiriot.sharon9986@aol.com", "exhfbwzrqbqjsanq"));
        emailUsers.add(new EmailUser("smtp.sina.com", "gmywgw@sina.com", "0913ca85741ebe91"));

        ExecutorService executor = Executors.newFixedThreadPool(10);

        for (EmailUser emailUser : emailUsers) {
            executor.submit(() -> checkEmail(emailUser.getHost(), emailUser.getEmail(), emailUser.getPassword()));
        }

        executor.shutdown();
    }

    public static void checkEmail(String host, String email, String password) {
        Properties props = new Properties();
        props.put("mail.transport.protocol", "smtp");
        props.put("mail.smtp.host", host);
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.ssl.enable", "true");
        props.put("mail.smtp.starttls.enable", "true");

        Session session = Session.getDefaultInstance(props);

        Transport transport = null;
        try {
            transport = session.getTransport();
            transport.connect(email, password);
            System.out.println(email + "认证成功" + session.toString());
        } catch (MessagingException e) {
            e.printStackTrace();
            System.out.println(email + "认证失败" + session.toString());
        } finally {
            if (transport != null) {
                try {
                    transport.close();
                } catch (MessagingException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

这只是一个简单的示例代码,仅演示了如何将任务提交给线程池执行,并创建了一个单独的Session对象。你可能需要根据自己的需求进一步优化代码。

可能是由于邮件服务器对IP越多尝试认证失败时的行为限制而导致的。在这种情况下,当您尝试使用多个IP地址进行邮件服务器认证时,邮件服务器可能会因为认为有恶意登录行为或攻击而拒绝您的请求,这样将触发邮件服务器抛出异常通知您排除限制或等待一段时间后重试。

为了避免这种情况,您可以尝试使用单个IP地址或IP地址池,并确保为每个SMTP服务器设置唯一的帐户。您也可以尝试排除认证失败错误和等待一段时间后再尝试认证。

如果您正在测试多个SMTP服务器,请确保您的测试脚本使用一个IP地址或IP地址池,并且每个SMTP服务器有一个唯一的帐户。您也可以尝试使用代理服务器以减少请求到邮件服务器的IP地址数量。


package com.itheima.utlis;

import com.itheima.pojo.EmailUser;

import javax.mail.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class EmailUtis {

    private static ArrayList<String> logs = new ArrayList<>(); // 日志缓冲区
    private static ArrayList<EmailUser> emailUsers = new ArrayList<>(); // 邮箱用户列表

    public static void main(String[] args) throws InterruptedException {

        Collections.addAll(emailUsers,
                new EmailUser("smtp.aol.com", "thiriot.sharon9986@aol.com", "exhfbwzrqbqjsanq"),
                new EmailUser("smtp.aol.com", "thiriot.sharon9986@aol.com", "exhfbwzrqbqjsanq"),
                new EmailUser("smtp.sina.com", "gmywgw@sina.com", "0913ca85741ebe91"),
                new EmailUser("smtp.sina.com", "gmywgw@sina.com", "0913ca85741ebe91"));

        emailUsers = (ArrayList<EmailUser>) Collections.synchronizedList(emailUsers);

        int taskNum = emailUsers.size();
        CountDownLatch countDownLatch = new CountDownLatch(taskNum);

        ExecutorService executor = Executors.newFixedThreadPool(10); // 10 threads in pool

        for (EmailUser emailUser : emailUsers) {
            Runnable task = new Runnable() {
                @Override
                public void run() {
                    boolean authenticated = checkEmail(emailUser.getHost(), emailUser.getEmail(), emailUser.getPassword());
                    if (authenticated) {
                        logs.add(emailUser.getEmail() + " 认证成功");
                    } else {
                        logs.add(emailUser.getEmail() + " 认证失败");
                    }
                    countDownLatch.countDown();
                }
            };
            executor.execute(task);
        }
 
        countDownLatch.await(15, TimeUnit.MINUTES); // wait for all tasks to complete
        executor.shutdown(); // shut down the thread pool

        synchronized (logs) { // output logs in synchronized way
            for (String log : logs) {
                System.out.println(log);
            }
        }
    }

    /**
     * @param host     SMTP服务端地址,如qq邮箱为smtp.qq.com
     * @param email    邮箱名
     * @param password 邮箱注册码(非登录名,具体需根据邮箱到官网申请)
     * @return 如果可用返回true
     * @throws MessagingException
     */
    public static boolean checkEmail(String host, String email, String password) {
        Properties props = new Properties();

        props.put("mail.transport.protocol", "smtp");// 连接协议
        props.put("mail.smtp.host", host);// 主机名,必须要,也可以使用smtp.sina.com.cn
        //   props.put("mail.smtp.port", 465);// 端口号,写不写无所谓,不确定的情况下,可以不写
        props.put("mail.smtp.auth", "true");// 是否鉴权,必须要
        props.put("mail.smtp.ssl.enable", "true");// 设置是否使用ssl安全连接,一般都使用
        props.put("mail.smtp.starttls.enable", "true");

        Session session = Session.getDefaultInstance(props);
        // session.setDebug(true);

        Transport transport = null;
        try {
            transport = session.getTransport();
        } catch (NoSuchProviderException e) {
            e.printStackTrace();
        }

        try {
            transport.connect(email, password);
            return true;
        } catch (MessagingException e) {
            e.printStackTrace();
            return false;
        } finally {
            if (transport != null) {
                try {
                    transport.close();
                    props.clone();
                } catch (MessagingException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

给你改了一下,你试试

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 以下回答来自chatgpt:

    针对该问题,可能是由于只有先进去的账号已经占用了 SMTP 连接,导致后面的认证失败。解决方案可以考虑在每次认证时都创建一个新的 SMTP 连接,以避免被占用的连接影响后续认证。

    以下是使用 Java 实现创建新的 SMTP 连接的示例代码:

    import javax.mail.*;
    import javax.mail.internet.*;
    
    public class EmailSender {
        private static String HOST = "smtp.example.com"; // SMTP 服务器地址
        private static int PORT = 25; // SMTP 端口号
        private static String USERNAME = "your_username"; // SMTP 账号
        private static String PASSWORD = "your_password"; // SMTP 密码
    
        public static void main(String[] args) {
            // 创建邮件会话
            Properties props = new Properties();
            props.put("mail.smtp.host", HOST);
            props.put("mail.smtp.port", String.valueOf(PORT));
            props.put("mail.smtp.auth", "true");
            Session session = Session.getInstance(props, new Authenticator() {
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(USERNAME, PASSWORD);
                }
            });
    
            try {
                // 创建新的 SMTP 连接
                SMTPTransport transport = (SMTPTransport) session.getTransport("smtp");
                transport.connect(HOST, PORT, USERNAME, PASSWORD);
    
                // 发送邮件
                MimeMessage message = new MimeMessage(session);
                message.setFrom(new InternetAddress("sender@example.com"));
                message.setRecipients(Message.RecipientType.TO, InternetAddress.parse("receiver@example.com"));
                message.setSubject("Test Email");
                message.setText("This is a test email.");
                Transport.send(message);
    
                // 关闭 SMTP 连接
                transport.close();
            } catch (MessagingException e) {
                e.printStackTrace();
            }
        }
    }
    

    在每次发送邮件前,都创建一个新的 SMTP 连接,可以使用 session.getTransport("smtp") 方法获取 SMTPTransport 对象,再通过 transport.connect() 方法连接 SMTP 服务器。发送邮件后,调用 transport.close() 方法关闭 SMTP 连接即可。这样可以保证每次都使用全新的 SMTP 连接,避免被占用的连接影响后续认证。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^