diff --git a/apps/jetty/java/src/net/i2p/servlet/RequestWrapper.java b/apps/jetty/java/src/net/i2p/servlet/RequestWrapper.java
index c0e06f9c1b8d92ad00f179ffd235c06af59b225e..ffc7e306a4eb76211df06c86d5fcadfeabf5aff0 100644
--- a/apps/jetty/java/src/net/i2p/servlet/RequestWrapper.java
+++ b/apps/jetty/java/src/net/i2p/servlet/RequestWrapper.java
@@ -101,6 +101,7 @@ public class RequestWrapper {
 
 	/**
 	 * @return List of request parameter names
+	 * @throws IllegalStateException if the request is too large
 	 */
 	public Enumeration<String> getParameterNames() {
 		if (isMultiPartRequest) {
@@ -117,6 +118,7 @@ public class RequestWrapper {
 					log(se);
 				} catch (IllegalStateException ise) {
 					log(ise);
+					throw ise;
 				}
 			}
 			return cachedParameterNames.keys();
@@ -139,6 +141,9 @@ public class RequestWrapper {
 		return httpRequest.getContentType();
 	}
 
+	/**
+	 * @throws IllegalStateException if the request is too large
+	 */
 	public String getContentType( String partName )
 	{
 		String result = null;
@@ -153,6 +158,7 @@ public class RequestWrapper {
 				log(se);
 			} catch (IllegalStateException ise) {
 				log(ise);
+				throw ise;
 			}
 		}
 		return result;
@@ -162,6 +168,9 @@ public class RequestWrapper {
 		return httpRequest.getAttribute( string );
 	}
 
+	/**
+	 * @throws IllegalStateException if the request is too large
+	 */
 	public String getParameter( String name, String defaultValue )
 	{
 		String result = defaultValue;
@@ -192,6 +201,7 @@ public class RequestWrapper {
 					log(se);
 				} catch (IllegalStateException ise) {
 					log(ise);
+					throw ise;
 				} finally {
 					if (in != null) try { in.close(); } catch (IOException ioe) {}
 				}
@@ -204,6 +214,9 @@ public class RequestWrapper {
 		return result;
 	}
 
+	/**
+	 * @throws IllegalStateException if the request is too large
+	 */
 	public String getFilename(String partName )
 	{
 		String result = null;
@@ -218,11 +231,15 @@ public class RequestWrapper {
 				log(se);
 			} catch (IllegalStateException ise) {
 				log(ise);
+				throw ise;
 			}
 		}
 		return result;
 	}
 
+	/**
+	 * @throws IllegalStateException if the request is too large
+	 */
 	public InputStream getInputStream(String partName )
 	{
 		InputStream result = null;
@@ -237,6 +254,7 @@ public class RequestWrapper {
 				log(se);
 			} catch (IllegalStateException ise) {
 				log(ise);
+				throw ise;
 			}
 		}
 		return result;
diff --git a/apps/jetty/java/src/net/i2p/servlet/filters/XSSFilter.java b/apps/jetty/java/src/net/i2p/servlet/filters/XSSFilter.java
index b29892e70f6a7f85fb3f1b90b78d0704e00f948b..9fcce1aba043ac0ca3664990e252cb6e742c91de 100644
--- a/apps/jetty/java/src/net/i2p/servlet/filters/XSSFilter.java
+++ b/apps/jetty/java/src/net/i2p/servlet/filters/XSSFilter.java
@@ -9,6 +9,7 @@ import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
 /**
  *  @since 0.9.14
@@ -25,6 +26,14 @@ public class XSSFilter implements Filter {
     @Override
     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
         throws IOException, ServletException {
-        chain.doFilter(new XSSRequestWrapper((HttpServletRequest) request), response);
+        try {
+            chain.doFilter(new XSSRequestWrapper((HttpServletRequest) request), response);
+        } catch (IllegalStateException ise) {
+            // Multipart form error, probably file too big
+            // We need to send the error quickly, if we just throw a ServletException,
+            // the data keeps coming and the connection gets reset.
+            // This way we at least get the error to the browser.
+            ((HttpServletResponse)response).sendError(413, ise.getMessage());
+        }
     }
 }
diff --git a/apps/routerconsole/java/build.xml b/apps/routerconsole/java/build.xml
index fc97aa97b82284c6748b3eb11821eb293da36e75..7b1c2008fa4519a1b9bfedd289c957a326fdba28 100644
--- a/apps/routerconsole/java/build.xml
+++ b/apps/routerconsole/java/build.xml
@@ -448,7 +448,7 @@
         <!-- Add multipart config to servlets that need them -->
         <property name="__match1" value="&lt;servlet-class&gt;net.i2p.router.web.jsp." />
         <property name="__match2" value="_jsp&lt;/servlet-class&gt;" />
-        <property name="__class1" value="${__match1}configclients${__match2}" />
+        <property name="__class1" value="${__match1}configplugins${__match2}" />
         <property name="__class2" value="${__match1}configfamily${__match2}" />
         <property name="__class3" value="${__match1}configreseed${__match2}" />
         <property name="__multipart" value="&#10;
diff --git a/apps/susimail/src/WEB-INF/web.xml b/apps/susimail/src/WEB-INF/web.xml
index 24d073f0e835db1b1941e1a7b20417649155f2c4..83b96a1e2bb14b9ebf47c1abc675657ee7517247 100644
--- a/apps/susimail/src/WEB-INF/web.xml
+++ b/apps/susimail/src/WEB-INF/web.xml
@@ -17,9 +17,10 @@
     <servlet-name>SusiMail</servlet-name>
     <servlet-class>i2p.susi.webmail.WebMail</servlet-class>
     <multipart-config>
-      <max-file-size>67108864</max-file-size>
-      <max-request-size>67108864</max-request-size>
-      <file-size-threshold>262144</file-size-threshold>
+      <!-- 23 MB. See SMTPClient for discussion -->
+      <max-file-size>24117248</max-file-size>
+      <max-request-size>24117248</max-request-size>
+      <file-size-threshold>131072</file-size-threshold>
     </multipart-config>
   </servlet>
   <servlet-mapping>
diff --git a/apps/susimail/src/src/i2p/susi/webmail/Attachment.java b/apps/susimail/src/src/i2p/susi/webmail/Attachment.java
index 3cccc447ccaa462a5916c2791fbc425391f4d1da..5fde45975910937ab7d067324b13fe08b8950e51 100644
--- a/apps/susimail/src/src/i2p/susi/webmail/Attachment.java
+++ b/apps/susimail/src/src/i2p/susi/webmail/Attachment.java
@@ -73,7 +73,15 @@ public class Attachment {
 	}
 
 	/**
-         * Delete the data file
+	 * The unencoded size
+	 * @since 0.9.33
+	 */
+	public long getSize() {
+		return data.length();
+	}
+
+	/**
+	 * Delete the data file
 	 * @since 0.9.33
 	 */
 	public void deleteData() {
diff --git a/apps/susimail/src/src/i2p/susi/webmail/WebMail.java b/apps/susimail/src/src/i2p/susi/webmail/WebMail.java
index 044bb6f26898db8438862cfaf52e3c2570d71b1f..eec8f675be95b831efbcebd46bc7ad24773e3cd4 100644
--- a/apps/susimail/src/src/i2p/susi/webmail/WebMail.java
+++ b/apps/susimail/src/src/i2p/susi/webmail/WebMail.java
@@ -1648,16 +1648,22 @@ public class WebMail extends HttpServlet
 			sessionObject.isMobile = isMobile;
 			
 			if (isPOST) {
-				String nonce = request.getParameter(SUSI_NONCE);
-				if (nonce == null || !sessionObject.isValidNonce(nonce)) {
-					// These two strings are already in the router console FormHandler,
-					// so translate with that bundle.
-					sessionObject.error = consoleGetString(
-						"Invalid form submission, probably because you used the 'back' or 'reload' button on your browser. Please resubmit.",
-						ctx)
-						+ '\n' +
-						consoleGetString("If the problem persists, verify that you have cookies enabled in your browser.",
-						ctx);
+				try {
+					String nonce = request.getParameter(SUSI_NONCE);
+					if (nonce == null || !sessionObject.isValidNonce(nonce)) {
+						// These two strings are already in the router console FormHandler,
+						// so translate with that bundle.
+						sessionObject.error = consoleGetString(
+							"Invalid form submission, probably because you used the 'back' or 'reload' button on your browser. Please resubmit.",
+							ctx)
+							+ '\n' +
+							consoleGetString("If the problem persists, verify that you have cookies enabled in your browser.",
+							ctx);
+						isPOST = false;
+					}
+				} catch (IllegalStateException ise) {
+					// too big, can't get any parameters
+					sessionObject.error += ise.getMessage() + '\n';
 					isPOST = false;
 				}
 			}
@@ -2027,6 +2033,19 @@ public class WebMail extends HttpServlet
 			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);
 			body.append( "From: " + from + "\r\n" );
@@ -2040,9 +2059,7 @@ public class WebMail extends HttpServlet
 				sessionObject.error += e.getMessage();
 			}
 			String boundary = "_=" + I2PAppContext.getGlobalContext().random().nextLong();
-			boolean multipart = false;
-			if( sessionObject.attachments != null && !sessionObject.attachments.isEmpty() ) {
-				multipart = true;
+			if (multipart) {
 				body.append( "\r\nMIME-Version: 1.0\r\nContent-type: multipart/mixed; boundary=\"" + boundary + "\"\r\n\r\n" );
 			}
 			else {
diff --git a/apps/susimail/src/src/i2p/susi/webmail/smtp/SMTPClient.java b/apps/susimail/src/src/i2p/susi/webmail/smtp/SMTPClient.java
index 00f58f316b80877ba5bcaa3e92beb4271e4c0955..2383625a852486e3c7c4d2cf00ecc9ef113a2275 100644
--- a/apps/susimail/src/src/i2p/susi/webmail/smtp/SMTPClient.java
+++ b/apps/susimail/src/src/i2p/susi/webmail/smtp/SMTPClient.java
@@ -47,6 +47,20 @@ import net.i2p.data.DataHelper;
  */
 public class SMTPClient {
 	
+	/**
+	 *  31.84 MB
+	 *  smtp.postman.i2p as of 2017-12.
+	 *  @since 0.9.33
+	 */
+	public static final long DEFAULT_MAX_SIZE = 33388608;
+
+	/**
+	 *  About 23.25 MB.
+	 *  Base64 encodes 57 chars to 76 + \r\n on a line
+	 *  @since 0.9.33
+	 */
+	public static final long BINARY_MAX_SIZE = (long) ((DEFAULT_MAX_SIZE * 57.0d / 78) - 32*1024);
+
 	private Socket socket;
 	public String error;
 	private String lastResponse;