{"record":{"id":"7e56d30b34304a48","repo":"elunez/eladmin","slug":"error-7e56d3","errorCode":null,"errorMessage":"请先配置，再操作","messagePattern":"请先配置，再操作","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"eladmin-tools/src/main/java/me/zhengjie/service/impl/EmailServiceImpl.java","lineNumber":68,"sourceCode":"        if(!emailConfig.getPass().equals(old.getPass())){\n            // 对称加密\n            emailConfig.setPass(EncryptUtils.desEncrypt(emailConfig.getPass()));\n        }\n        return emailRepository.save(emailConfig);\n    }\n\n    @Override\n    @Cacheable(key = \"'config'\")\n    public EmailConfig find() {\n        Optional<EmailConfig> emailConfig = emailRepository.findById(1L);\n        return emailConfig.orElseGet(EmailConfig::new);\n    }\n\n    @Override\n    @Transactional(rollbackFor = Exception.class)\n    public void send(EmailVo emailVo, EmailConfig emailConfig){\n        if(emailConfig.getId() == null){\n            throw new BadRequestException(\"请先配置，再操作\");\n        }\n        // 封装\n        MailAccount account = new MailAccount();\n        // 设置用户\n        String user = emailConfig.getFromUser().split(\"@\")[0];\n        account.setUser(user);\n        account.setHost(emailConfig.getHost());\n        account.setPort(Integer.parseInt(emailConfig.getPort()));\n        account.setAuth(true);\n        try {\n            // 对称解密\n            account.setPass(EncryptUtils.desDecrypt(emailConfig.getPass()));\n        } catch (Exception e) {\n            throw new BadRequestException(e.getMessage());\n        }\n        account.setFrom(emailConfig.getUser()+\"<\"+emailConfig.getFromUser()+\">\");\n        // ssl方式发送\n        account.setSslEnable(true);","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/elunez/eladmin/blob/55fbf705956949697dbd68bf9003776609d3d029/eladmin-tools/src/main/java/me/zhengjie/service/impl/EmailServiceImpl.java#L50-L86","documentation":"Thrown by EmailServiceImpl.send(emailVo, emailConfig) when emailConfig.getId() == null — the caller passed a transient EmailConfig, which per find() only happens when no row with id=1 exists in the email config table (find() returns new EmailConfig() via orElseGet). So the admin has never saved SMTP settings; sending is refused before any SMTP connection is attempted.","triggerScenarios":"Triggering any flow that sends mail (e.g. the verification-code endpoint that calls verifyCode then emailService.send) on a system where the tools email config was never saved; find() is @Cacheable so an empty EmailConfig can also get cached under 'config' after a failed first lookup.","commonSituations":"Fresh deployment without the email config row; DB migration that dropped email_config; the cached empty config not invalidated after saving real config if save() doesn't @CachePut the same key; testing the 'send code' button before completing setup.","solutions":["Open the tools -> email config admin page and save host, port, fromUser, password (id becomes 1L).","Verify row id=1 exists in email_config and that find() now returns it (clear the 'config' cache key if a stale empty object was cached).","Ensure the config save path uses @CachePut(key='config') (mirroring AliPayServiceImpl) so the empty cached entry is replaced on save.","Sequence smoke tests: configure email before any test that sends mail."],"exampleFix":"// before\npublic void send(EmailVo emailVo, EmailConfig emailConfig){\n    if(emailConfig.getId() == null){\n        throw new BadRequestException(\"请先配置，再操作\");\n    }\n\n// after (caller-side, in the verify-code flow):\nEmailConfig config = emailService.find();\nif(config.getId() == null){\n    throw new BadRequestException(\"邮箱服务未配置，请联系管理员先完成邮箱设置\");\n}\nemailService.send(emailService.sendEmail(email, key), config);","handlingStrategy":"validation","validationCode":"// before any send flow\nEmailConfig config = emailService.find();\nif (config.getId() == null) {\n    throw new BadRequestException(\"邮箱未配置，请先在后台保存邮箱设置\");\n}\nemailService.send(emailVo, config);","typeGuard":null,"tryCatchPattern":"try { emailService.send(emailVo, config); } catch (BadRequestException e) { if (\"请先配置，再操作\".equals(e.getMessage())) { /* route to email config page; this is setup, not transient */ } }","preventionTips":["Include email config in environment provisioning; the feature depends on row id=1 existing.","Save config through the admin UI (never raw DB inserts) so the password gets encrypted and cache updated.","Clear the 'config' cache key when fixing config directly in the database."],"tags":["email","smtp","configuration","cache"],"backgroundTag":null,"analyzedSha":"55fbf705956949697dbd68bf9003776609d3d029","analyzedAt":"2026-08-14T11:56:12.758Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}