use of i2p.susi.webmail.encoding.EncodingException in project i2p.i2p by i2p.
the class SMTPClient method sendMail.
/**
* @param body without the attachments
* @param attachments may be null
* @param boundary non-null if attachments is non-null
* @return success
*/
public boolean sendMail(String host, int port, String user, String pass, String sender, String[] recipients, StringBuilder body, List<Attachment> attachments, String boundary) {
boolean mailSent = false;
boolean ok = true;
Writer out = null;
try {
socket = InternalSocket.getSocket(host, port);
} catch (IOException e) {
error += _t("Cannot connect") + " (" + host + ':' + port + ") : " + e.getMessage() + '\n';
ok = false;
}
try {
// AUTH ref: RFC 4954
if (ok) {
socket.setSoTimeout(120 * 1000);
int result = sendCmd(null);
if (result != 220) {
if (result != 0)
error += _t("Server refused connection") + " (" + result + ")\n";
else
error += _t("Cannot connect") + " (" + host + ':' + port + ")\n";
ok = false;
}
}
if (ok) {
sendCmdNoWait("EHLO localhost");
socket.getOutputStream().flush();
socket.setSoTimeout(60 * 1000);
Result r = getFullResult();
if (r.result == 250) {
String[] caps = DataHelper.split(r.recv, "\r");
for (String c : caps) {
if (c.equals("PIPELINING")) {
supportsPipelining = true;
Debug.debug(Debug.DEBUG, "Server supports pipelining");
} else if (c.startsWith("SIZE ")) {
try {
maxSize = Long.parseLong(c.substring(5));
Debug.debug(Debug.DEBUG, "Server max size: " + maxSize);
} catch (NumberFormatException nfe) {
}
} else if (c.equals("8BITMIME")) {
// unused, see encoding/EightBit.java
eightBitMime = true;
Debug.debug(Debug.DEBUG, "Server supports 8bitmime");
}
}
} else {
error += _t("Server refused connection") + " (" + r + ")\n";
ok = false;
}
}
if (ok && maxSize < DEFAULT_MAX_SIZE) {
Debug.debug(Debug.DEBUG, "Rechecking with new max size");
// recalculate whether we'll fit
// copied from WebMail
long total = body.length();
if (attachments != null && !attachments.isEmpty()) {
for (Attachment a : attachments) {
total += a.getSize();
}
}
long binaryMax = (long) ((maxSize * 57.0d / 78) - 32 * 1024);
if (total > binaryMax) {
ok = false;
error += _t("Email is too large, max is {0}", DataHelper.formatSize2(binaryMax, false) + 'B') + '\n';
}
}
if (ok) {
// RFC 4954 says AUTH must be the last but let's assume
// that includes the user/pass on following lines
List<SendExpect> cmds = new ArrayList<SendExpect>();
cmds.add(new SendExpect("AUTH LOGIN", 334));
cmds.add(new SendExpect(base64.encode(user), 334));
cmds.add(new SendExpect(base64.encode(pass), 235));
if (sendCmds(cmds) != 3) {
error += _t("Login failed") + '\n';
ok = false;
}
}
if (ok) {
List<SendExpect> cmds = new ArrayList<SendExpect>();
cmds.add(new SendExpect("MAIL FROM: " + sender, 250));
for (int i = 0; i < recipients.length; i++) {
cmds.add(new SendExpect("RCPT TO: " + recipients[i], 250));
}
cmds.add(new SendExpect("DATA", 354));
if (sendCmds(cmds) != cmds.size()) {
// TODO which recipient?
error += _t("Mail rejected") + '\n';
ok = false;
}
}
if (ok) {
// in-memory replace, no copies
DataHelper.replace(body, "\r\n.\r\n", "\r\n..\r\n");
// socket.getOutputStream().write(DataHelper.getUTF8(body));
// socket.getOutputStream().write(DataHelper.getASCII("\r\n.\r\n"));
// Do it this way so we don't double the memory
out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "ISO-8859-1"));
out.write(body.toString());
// and check the max total size
if (attachments != null && !attachments.isEmpty()) {
for (Attachment attachment : attachments) {
String encodeTo = attachment.getTransferEncoding();
Encoding encoding = EncodingFactory.getEncoding(encodeTo);
if (encoding == null)
throw new EncodingException(_t("No Encoding found for {0}", encodeTo));
// ref: https://blog.nodemailer.com/2017/01/27/the-mess-that-is-attachment-filenames/
// ref: RFC 2231
// split Content-Disposition into 3 lines to maximize room
// TODO filename*0* for long names...
String name = attachment.getFileName();
String name2 = FilenameUtil.sanitizeFilename(name);
String name3 = FilenameUtil.encodeFilenameRFC5987(name);
out.write("\r\n--" + boundary + "\r\nContent-type: " + attachment.getContentType() + "\r\nContent-Disposition: attachment;\r\n\tfilename=\"" + name2 + "\";\r\n\tfilename*=" + name3 + "\r\nContent-Transfer-Encoding: " + attachment.getTransferEncoding() + "\r\n\r\n");
InputStream in = null;
try {
in = attachment.getData();
encoding.encode(in, out);
} finally {
if (in != null)
try {
in.close();
} catch (IOException ioe) {
}
}
}
out.write("\r\n--" + boundary + "--\r\n");
}
out.write("\r\n.\r\n");
out.flush();
socket.setSoTimeout(0);
int result = sendCmd(null);
if (result == 250)
mailSent = true;
else
error += _t("Error sending mail") + " (" + result + ")\n";
}
} catch (IOException e) {
error += _t("Error sending mail") + ": " + e.getMessage() + '\n';
}
if (!mailSent && lastResponse.length() > 0) {
String[] lines = DataHelper.split(lastResponse, "\r");
for (int i = 0; i < lines.length; i++) error += lines[i] + '\n';
}
sendCmd("QUIT", false);
if (socket != null) {
try {
socket.close();
} catch (IOException e1) {
}
if (out != null)
try {
out.close();
} catch (IOException ioe) {
}
}
return mailSent;
}
use of i2p.susi.webmail.encoding.EncodingException in project i2p.i2p by i2p.
the class WebMail method sendMail.
/**
* @param sessionObject
* @param request
* @return success
*/
private static boolean sendMail(SessionObject sessionObject, RequestWrapper request) {
boolean ok = true;
String from = request.getParameter(NEW_FROM);
String to = request.getParameter(NEW_TO);
String cc = request.getParameter(NEW_CC);
String bcc = request.getParameter(NEW_BCC);
String subject = request.getParameter(NEW_SUBJECT, _t("no subject"));
String text = request.getParameter(NEW_TEXT, "");
boolean fixed = Boolean.parseBoolean(Config.getProperty(CONFIG_SENDER_FIXED, "true"));
if (fixed) {
String domain = Config.getProperty(CONFIG_SENDER_DOMAIN, "mail.i2p");
from = "<" + sessionObject.user + "@" + domain + ">";
}
ArrayList<String> toList = new ArrayList<String>();
ArrayList<String> ccList = new ArrayList<String>();
ArrayList<String> bccList = new ArrayList<String>();
ArrayList<String> recipients = new ArrayList<String>();
String sender = null;
if (from == null || !Mail.validateAddress(from)) {
ok = false;
sessionObject.error += _t("Found no valid sender address.") + '\n';
} else {
sender = Mail.getAddress(from);
if (sender == null || sender.length() == 0) {
ok = false;
sessionObject.error += _t("Found no valid address in \\''{0}\\''.", quoteHTML(from)) + '\n';
}
}
ok = Mail.getRecipientsFromList(toList, to, ok);
ok = Mail.getRecipientsFromList(ccList, cc, ok);
ok = Mail.getRecipientsFromList(bccList, bcc, ok);
recipients.addAll(toList);
recipients.addAll(ccList);
recipients.addAll(bccList);
String bccToSelf = request.getParameter(NEW_BCC_TO_SELF);
boolean toSelf = "1".equals(bccToSelf);
// save preference in session
sessionObject.bccToSelf = toSelf;
if (toSelf)
recipients.add(sender);
if (toList.isEmpty()) {
ok = false;
sessionObject.error += _t("No recipients found.") + '\n';
}
Encoding qp = EncodingFactory.getEncoding("quoted-printable");
Encoding hl = EncodingFactory.getEncoding("HEADERLINE");
if (qp == null) {
ok = false;
// can't happen, don't translate
sessionObject.error += "Internal error: Quoted printable encoder not available.";
}
if (hl == null) {
ok = false;
// can't happen, don't translate
sessionObject.error += "Internal error: Header line encoder not available.";
}
long total = text.length();
boolean multipart = sessionObject.attachments != null && !sessionObject.attachments.isEmpty();
if (multipart) {
for (Attachment a : sessionObject.attachments) {
total += a.getSize();
}
}
if (total > SMTPClient.BINARY_MAX_SIZE) {
ok = false;
sessionObject.error += _t("Email is too large, max is {0}", DataHelper.formatSize2(SMTPClient.BINARY_MAX_SIZE, false) + 'B') + '\n';
}
if (ok) {
StringBuilder body = new StringBuilder(1024);
I2PAppContext ctx = I2PAppContext.getGlobalContext();
body.append("Date: " + RFC822Date.to822Date(ctx.clock().now()) + "\r\n");
// todo include real names, and headerline encode them
body.append("From: " + from + "\r\n");
Mail.appendRecipients(body, toList, "To: ");
Mail.appendRecipients(body, ccList, "Cc: ");
try {
body.append(hl.encode("Subject: " + subject.trim()));
} catch (EncodingException e) {
ok = false;
sessionObject.error += e.getMessage();
}
String boundary = "_=" + ctx.random().nextLong();
if (multipart) {
body.append("MIME-Version: 1.0\r\nContent-type: multipart/mixed; boundary=\"" + boundary + "\"\r\n\r\n");
} else {
body.append("MIME-Version: 1.0\r\nContent-type: text/plain; charset=\"utf-8\"\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n");
}
try {
// TODO pass the text separately to SMTP and let it pick the encoding
if (multipart)
body.append("--" + boundary + "\r\nContent-type: text/plain; charset=\"utf-8\"\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n");
body.append(qp.encode(text));
} catch (EncodingException e) {
ok = false;
sessionObject.error += e.getMessage();
}
// set to the StringBuilder so SMTP can replace() in place
sessionObject.sentMail = body;
if (ok) {
SMTPClient relay = new SMTPClient();
if (relay.sendMail(sessionObject.host, sessionObject.smtpPort, sessionObject.user, sessionObject.pass, sender, recipients.toArray(new String[recipients.size()]), sessionObject.sentMail, sessionObject.attachments, boundary)) {
sessionObject.info += _t("Mail sent.");
sessionObject.sentMail = null;
sessionObject.clearAttachments();
} else {
ok = false;
sessionObject.error += relay.error;
}
}
}
return ok;
}
Aggregations