监听邮件转发飞书机器人(webhook)

仓库地址

        MailListen: 监听邮箱未读文件,对满足条件的邮件处理转发给webhook地址 (gitee.com)

        欢迎一起交流学习

业务背景

        当服务器的告警日志信息发送到邮箱时,我们无法及时查收,这可能导致问题扩大,需要一个全天候的服务监听邮箱的邮件

服务流程

        定时执行邮件列表过滤流程,当检测到是未读的告警日志邮件时,将邮件富文本转为普通文本,经过post json方式推送至webhook地址(这里使用飞书机器人)

        这样的做法可以保证日志信息的完整,并且在服务宕机时,还可以在重启时继续无损运行

邮件列表过滤

        将符合条件的邮件(主题包含yml文件中配置的filterTitle字符串)的部件组合为一个String字符串,注意这里无法处理附件

    public void fetchMail() throws InterruptedException {

        if (OPEN) {
            System.out.println("邮件转发已被关闭");
            return;
        }

        if(LOCK.tryLock(1, TimeUnit.SECONDS)){

            try {
                openFolder();

                int size = folder.getMessageCount();

                System.out.println("邮件个数:" + size);

                if (skip != null && skip && messageLastSize != null && messageLastSize == size) {
                    System.out.println("跳过未读邮件检测");
                } else {
                    messageLastSize = size;
                    for (int i = 0; i < size; i++) {

                        Message message = folder.getMessage(size - i);
                        String subject = message.getSubject();

                        //判断主题包含WGCLOUD
                        if (!subject.contains(filterTitle)) {
                            continue;
                        }

                        if (message.getFlags().contains(Flags.Flag.SEEN)) {
                            continue;
                        }

                        System.out.println("未读邮件为:");

                        String from = message.getFrom()[0].toString();
                        Date date = message.getSentDate();
                        System.out.println("\tFrom: \t" + from.replaceAll("<.+?>", ""));
                        System.out.println("\tSubject: \t" + subject);
                        System.out.println("\tDate: \t" + date);
                        MimeMultipart mimeMultipart = (MimeMultipart) message.getContent();

                        StringBuilder text = new StringBuilder();

                        // 遍历部件列表
                        for (int j = 0; j < mimeMultipart.getCount(); j++) {
                            BodyPart bodyPart = mimeMultipart.getBodyPart(j);

                            // 检查部件的内容类型
                            if (bodyPart.isMimeType("text/plain")) {
                                text.append((String) bodyPart.getContent());
                            } else if (bodyPart.isMimeType("text/html")) {
                                text.append((String) bodyPart.getContent());
                            }

                        }

                        System.out.println(sendFeiShuBot.sendMessageToBot(text.toString()));
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                System.out.println("接收完毕!");
                System.out.println("释放ReentrantLock锁");
                LOCK.unlock();
            }
        }else{
            System.out.println("ReentrantLock锁被占用,跳过此次定时任务");
        }
    }

发送webhook

        需要发送的文本经过正则过滤处理后,post给webHookUrl地址

        regexStr在yml文件中配置

public String sendMessageToBot(String text){

        System.out.println("接收到发送任务:" + text);
        text = text.replaceAll("[\\\\]", " ");
        text = text.replaceAll("[\b\r\n\t\"]", " ");
        text = text.replaceAll("<[^>]+>"," ");
        text = text.replaceAll(regexStr,"");
        System.out.println("处理后的文本:" + text);

        OkHttpClient client = new OkHttpClient().newBuilder()
                .build();

        MediaType mediaType = MediaType.parse("application/json");

        String json =
                "{\n" +
                "    \"msg_type\": \"text\",\n" +
                "    \"content\":{\n" +
                "        \"text\":\"" + text +"\"\n" +
                "    }\n" +
                "}";

        RequestBody body = RequestBody.create(mediaType, json);

        Request request = new Request.Builder()
                .url(HOST)
                .post(body)
                .build();

        try {
            System.out.println("已发送请求:" + json);
            Response response = client.newCall(request).execute();
            return Objects.requireNonNull(response.body()).string().contains("success") ?"success": Objects.requireNonNull(response.body()).string();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

    }

定时与接口

        Appilcation的内容包含下面的接口和定时任务

        需要更复杂处理的可以自己按照需求修改

	@Bean
	public TaskScheduler scheduler() {
		ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
		taskScheduler.setPoolSize(10);
		taskScheduler.setThreadNamePrefix("MailServer");
		return taskScheduler;
	}

	@Resource
	private ListenMail listenMail;

	@Scheduled(cron = "0/10 * * * * ? ")
	public void mailHandle(){
		listenMail.fetchMail();
	}

	@RequestMapping("/openListen")
	public String openMailListen(){
		return listenMail.startListen()?"邮件转发已开启":"邮件转发开启失败";
	}

	@RequestMapping("/closeListen")
	public String closeMailListen(){
		return listenMail.stopListen()?"邮件转发已关闭":"邮件转发关闭失败";
	}

	@RequestMapping("/statusListen")
	public String getMailStatus(){
		return !listenMail.getOpen()?"邮箱监听中":"邮箱静默中";
	}

	@RequestMapping("/mailConfig")
	public String configMail(){
		return listenMail.getConfig();
	}

	@RequestMapping("/checkPassword")
	public String checkPassword(String password){
		return listenMail.checkPassword(password)?"密码一致":"密码不一致";
	}

	@RequestMapping("/checkWebHook")
	public String checkWebHook(String url){
		return listenMail.checkWebHook(url)?"webhook地址一致":"webhook地址不一致";
	}

yml 配置

        服务运行在3333端口,下面host为你邮箱的接受邮件服务器地址

        这里以qq邮箱的imap和飞书机器人为例

        注意授权码需要在邮箱设置中开启,详细可以百度一下

        skip参数用于判断是否在邮件数量不变时跳过检测,这一步可以在邮件数量大的情况下大大节省时间

        filterTitle参数用于判断邮箱是否是所需邮件,它会用于与邮件的主题对比,如果包含则是

server:
  port: 3333
spring:
  application:
    name: listenMailServer
listen:
  mail:
    host: imap.qq.com
    port: 993
    usermail: axinfree@qq.com
    password: xxxx #邮箱授权码,不是账号密码
    protocol: imap
    folder: INBOX #获取的邮箱文件夹,如未对邮箱做特别设置,默认INBOX即可
    filterTitle: "WGCLOUD" #邮件检索条件,包含这段字符串的未读邮箱才会被提取数据并发送
    skip: true #ture表示开启,当开启时,若检测到邮件数量没有变化,会跳过检测未读邮件的步骤
send:
  webHookUrl: https://open.feishu.cn/open-apis/bot/v2/hook/xxxx
  regexStr: "WGCLOUD 敬上" #发送webhook之前被替换摘除的文本 如: regexStr = “2” ‘123465’-> ’13465‘

效果图

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱飞的男孩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值