NutzCN Logo
问答 验证邮件一直提示发送失败 我的设置应该是对的
发布于 2836天前 作者 qq_b952b6da 2944 次浏览 复制 上一个帖子 下一个帖子
标签:

package net.wendal.nutzbook.module;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.sql.SQLException;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import net.wendal.nutzbook.bean.UserProfile;
import net.wendal.nutzbook.util.Toolkit;

import org.apache.commons.logging.Log;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.DaoException;
import org.nutz.dao.FieldFilter;
import org.nutz.dao.util.Daos;
import org.nutz.img.Images;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.Mvcs;
import org.nutz.mvc.Scope;
import org.nutz.mvc.adaptor.JsonAdaptor;
import org.nutz.mvc.annotation.AdaptBy;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Attr;
import org.nutz.mvc.annotation.By;
import org.nutz.mvc.annotation.Filters;
import org.nutz.mvc.annotation.GET;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.POST;
import org.nutz.mvc.annotation.Param;
import org.nutz.mvc.filter.CheckSession;
import org.nutz.mvc.impl.AdaptorErrorContext;
import org.nutz.mvc.upload.TempFile;
import org.nutz.mvc.upload.UploadAdaptor;

@IocBean
@At("/user/profile")
@Filters(@By(type=CheckSession.class, args={"me", "/"})) // 检查当前Session是否带me这个属性
public class UserProfileModule extends BaseModule {

@At
public UserProfile get(@Attr(scope=Scope.SESSION, value="me")int userId) {
    UserProfile profile = Daos.ext(dao, FieldFilter.locked(UserProfile.class, "avatar")).fetch(UserProfile.class, userId);
    if (profile == null) {
        profile = new UserProfile();
        profile.setUserId(userId);
        profile.setCreateTime(new Date());
        profile.setUpdateTime(new Date());
        dao.insert(profile);
    }
    return profile;
}

@At
@AdaptBy(type=JsonAdaptor.class)
@Ok("void")
public void update(@Param("..")UserProfile profile, @Attr(scope=Scope.SESSION, value="me")int userId) {
    if (profile == null)
        return;
    profile.setUserId(userId);//修正userId,防止恶意修改其他用户的信息
    profile.setUpdateTime(new Date());
    profile.setAvatar(null); // 不准通过这个方法更新
    UserProfile old = get(userId);
    // 检查email相关的更新
    if (old.getEmail() == null) {
        // 老的邮箱为null,所以新的肯定是未check的状态
        profile.setEmailChecked(false);
    } else {
        if (profile.getEmail() == null) {
            profile.setEmail(old.getEmail());
            profile.setEmailChecked(old.isEmailChecked());
        } else if (!profile.getEmail().equals(old.getEmail())) {
            // 设置新邮箱,果断设置为未检查状态
            profile.setEmailChecked(false);
        } else {
            profile.setEmailChecked(old.isEmailChecked());
        }
    }
    Daos.ext(dao, FieldFilter.create(UserProfile.class, null, "avatar", true)).update(profile);
}

@AdaptBy(type=UploadAdaptor.class, args={"${app.root}/WEB-INF/tmp/user_avatar", "8192", "utf-8", "20000", "102400"})
@POST
@Ok(">>:/user/profile")
@At("/avatar")
public void uploadAvatar(@Param("file")TempFile tf,
        @Attr(scope=Scope.SESSION, value="me")int userId,
        AdaptorErrorContext err) {
    String msg = null;
    if (err != null && err.getAdaptorErr() != null) {
        msg = "文件大小不符合规定";
    } else if (tf == null) {
        msg = "空文件";
    } else {
        UserProfile profile = get(userId);
        try {
            BufferedImage image = Images.read(tf.getFile());
            image = Images.zoomScale(image, 128, 128, Color.WHITE);
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            Images.writeJpeg(image, out, 0.8f);
            profile.setAvatar(out.toByteArray());
            dao.update(profile, "^avatar$");
        } catch(DaoException e) {

// Log.info("System Error", e);
msg = "系统错误";
} catch (Throwable e) {
msg = "图片格式错误";
}
}

    if (msg != null)
        Mvcs.getHttpSession().setAttribute("upload-error-msg", msg);
}

@Ok("raw:jpg")
@At("/avatar")
@GET
public Object readAvatar(@Attr(scope=Scope.SESSION, value="me")int userId, HttpServletRequest req) throws SQLException {
    UserProfile profile = Daos.ext(dao, FieldFilter.create(UserProfile.class, "^avatar$")).fetch(UserProfile.class, userId);
    if (profile == null || profile.getAvatar() == null) {
        return new File(req.getServletContext().getRealPath("/rs/user_avatar/none.jpg"));
    }
    return profile.getAvatar();
}

@At("/")
@GET
@Ok("jsp:jsp.user.profile")
public UserProfile index(@Attr(scope=Scope.SESSION, value="me")int userId) {
    return get(userId);
}

@At("/active/mail")
@POST
public Object activeMail(@Attr(scope=Scope.SESSION, value="me")int userId,
        HttpServletRequest req) {
    NutMap re = new NutMap();
    UserProfile profile = get(userId);
    if (Strings.isBlank(profile.getEmail())) {
        return re.setv("ok", false).setv("msg", "你还没有填邮箱啊!");
    }
    String token = String.format("%s,%s,%s", userId, profile.getEmail(), System.currentTimeMillis());
    token = Toolkit._3DES_encode(emailKEY, token.getBytes());
    String url = req.getRequestURL() + "?token=" + token;
    String html = "<div>如果无法点击,请拷贝一下链接到浏览器中打开<p/>验证链接 %s</div>";
    html = String.format(html, url, url);
    try {
        boolean ok = emailService.send(profile.getEmail(), "XXX 验证邮件 by Nutzbook", html);
        if (!ok) {
            return re.setv("ok", false).setv("msg", "发送失败");
        }
    } catch (Throwable e) {

// log.debug("发送邮件失败", e);
return re.setv("ok", false).setv("msg", "发送失败");
}
return re.setv("ok", true);
}
@Filters // 不需要先登录,很明显...
@At("/active/mail")
@GET
@Ok("raw") // 为了简单起见,这里直接显示验证结果就好了
public String activeMailCallback(@Param("token")String token, HttpSession session) {
if (Strings.isBlank(token)) {
return "请不要直接访问这个链接!!!";
}
if (token.length() < 10) {
return "非法token";
}
try {
token = Toolkit._3DES_decode(emailKEY, Toolkit.hexstr2bytearray(token));
if (token == null)
return "非法token";
String[] tmp = token.split(",", 3);
if (tmp.length != 3 || tmp[0].length() == 0 || tmp[1].length() == 0 || tmp[2].length() == 0)
return "非法token";
long time = Long.parseLong(tmp[2]);
if (System.currentTimeMillis() - time > 10*60*1000) {
return "该验证链接已经超时";
}
int userId = Integer.parseInt(tmp[0]);
Cnd cnd = Cnd.where("userId", "=", userId).and("email", "=", tmp[1]);
int re = dao.update(UserProfile.class, Chain.make("emailChecked", true), cnd);
if (re == 1) {
return "验证成功";
}
return "验证失败!!请重新验证!!";
} catch (Throwable e) {
// log.debug("检查token时出错", e);
return "非法token";
}
}
}

mail.HostName=smtp.163.com
mail.SmtpPort=465
mail.UserName=cjw0821
mail.Password=**********
mail.SSLOnConnect=true
mail.From=cjw0821@163.com
mail.charset=UTF-8

17 回复

用阿里云邮进行测试. 不要再尝试163/126/QQ邮箱了.

@wendal 阿里云邮箱无法设置授权码啊

@wendal 阿里云邮箱依然发送失败

贴报错信息

2017-02-16 16:32:29,199 net.wendal.nutzbook.service.EmailServiceImpl.send(EmailServiceImpl.java:29) INFO  - send email fail
org.apache.commons.mail.EmailException: At least one receiver address required
	at org.apache.commons.mail.Email.buildMimeMessage(Email.java:1340)
	at org.apache.commons.mail.MultiPartEmail.buildMimeMessage(MultiPartEmail.java:254)
	at org.apache.commons.mail.HtmlEmail.buildMimeMessage(HtmlEmail.java:516)
	at org.apache.commons.mail.ImageHtmlEmail.buildMimeMessage(ImageHtmlEmail.java:108)
	at org.apache.commons.mail.Email.send(Email.java:1447)
	at net.wendal.nutzbook.service.EmailServiceImpl.send(EmailServiceImpl.java:23)
	at net.wendal.nutzbook.module.UserProfileModule.activeMail(UserProfileModule.java:158)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.nutz.mvc.impl.processor.MethodInvokeProcessor.process(MethodInvokeProcessor.java:25)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.AdaptorProcessor.process(AdaptorProcessor.java:33)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.ActionFiltersProcessor.process(ActionFiltersProcessor.java:58)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.integration.shiro.NutShiroProcessor.process(NutShiroProcessor.java:126)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.ModuleProcessor.process(ModuleProcessor.java:123)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.EncodingProcessor.process(EncodingProcessor.java:27)
	at org.nutz.mvc.impl.processor.AbstractProcessor.doNext(AbstractProcessor.java:44)
	at org.nutz.mvc.impl.processor.UpdateRequestAttributesProcessor.process(UpdateRequestAttributesProcessor.java:15)
	at org.nutz.mvc.impl.NutActionChain.doChain(NutActionChain.java:44)
	at org.nutz.mvc.impl.ActionInvoker.invoke(ActionInvoker.java:67)
	at org.nutz.mvc.ActionHandler.handle(ActionHandler.java:31)
	at org.nutz.mvc.NutFilter.doFilter(NutFilter.java:198)
	at net.wendal.nutzbook.mvc.NutzBookNutFilter.doFilter(NutzBookNutFilter.java:38)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
	at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
	at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
	at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
	at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
	at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
	at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:509)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1104)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:684)
	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2508)
	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2497)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:745)
2017-02-16 16:32:44,254 org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:276) DEBUG - batch acquisition of 0 triggers

org.apache.commons.mail.EmailException: At least one receiver address required

问题出在 EmailServiceImpl.send, 是不是漏写一行? 贴出来看看

@wendal
我也在找EmailServiceImpl.send的错误

@IocBean(name="emailService")
public class EmailServiceImpl implements EmailService {

    private static final Log log = Logs.get();

    @Inject("refer:$ioc")
    protected Ioc ioc;

    public boolean send(String to, String subject, String html) {
        try {
            HtmlEmail email = ioc.get(HtmlEmail.class);
            email.setSubject(subject);
            email.setHtmlMsg(html);
            email.addTo(to);
            email.buildMimeMessage();
            email.sendMimeMessage();
            return true;
        } catch (Throwable e) {
            log.info("send email fail", e);
            return false;
        }
    }
}

我在email.setHtmlMsg(html);下面加个 email.send();也没用

debug一下, 看看email.addTo(to);是否有值

话说, 不是应该在MainSetup里面先测试一下吗? 怎么这么快就到EmailServiceImpl了

@wendal

Caused by: com.sun.mail.util.MailConnectException: Couldn't connect to host, port: smtp.163.com, 25; timeout 60000;
  nested exception is:
	java.net.ConnectException: Connection timed out: connect
	at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:2053)
	at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:697)
	at javax.mail.Service.connect(Service.java:386)
	at javax.mail.Service.connect(Service.java:245)
	at javax.mail.Service.connect(Service.java:194)
	at javax.mail.Transport.send0(Transport.java:253)
	at javax.mail.Transport.send(Transport.java:124)
	at org.apache.commons.mail.Email.sendMimeMessage(Email.java:1411)
	... 55 more
@IocBean(name="emailService")
public class EmailServiceImpl implements EmailService {

    private static final Log log = Logs.get();

    @Inject("refer:$ioc")
    protected Ioc ioc;

    public boolean send(String to, String subject, String html) {
        try {
            HtmlEmail email = ioc.get(HtmlEmail.class);
            email.setSubject(subject);
            email.setHtmlMsg(html);
            email.addTo(to);
            email.send();
            email.buildMimeMessage();
            email.sendMimeMessage();
            return true;
        } catch (Throwable e) {
            log.info("send email fail", e);
            return false;
        }
    }
}

另外 to的值就是我的邮箱 没错 还是提示发送失败。。

你改了啥?? 报错不一样了

@wendal 把 email.send();放到了 email.addTo(to);的前面。。

下面是正确的写法:

	public boolean send(String to, String subject, String html) {
		try {
			HtmlEmail email = ioc.get(HtmlEmail.class);
			email.setSubject(subject);
			email.setHtmlMsg(html);
			email.addTo(to);
			email.buildMimeMessage();
			email.sendMimeMessage();
			return true;
		} catch (Throwable e) {
			log.info("send email fail", e);
			return false;
		}
	}

顺序不能乱来的.

而且, 163使用smtp发邮件,是需要第三方客户端授权码的, 而且163邮箱的smtp/pop默认是关闭的.

若SSL开启, 端口是465

http://help.mail.163.com/faqDetail.do?code=d7a5dc8471cd0c0e8b4b8f4f8e49998b374173cfe9171305fa1ce630d7f67ac22dc0e9af8168582a

@wendal 授权码这些我都设置过了 SMTP/POP 我都开启了 还是不行。。代码刚改成你贴的了

Caused by: java.net.ConnectException: Connection timed out: connect
	at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
	at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85)
	at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
	at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
	at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
	at java.net.Socket.connect(Socket.java:589)
	at com.sun.mail.util.SocketFetcher.createSocket(SocketFetcher.java:310)
	at com.sun.mail.util.SocketFetcher.getSocket(SocketFetcher.java:236)
	at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:2019)
	... 61 more

一直提示 timeout 心累。。

换阿里云邮啊...

添加回复
请先登陆
回到顶部