pentaho/pentaho-kettle · error · KettleException
Mail.Error.MailServerEmpty
Error message
Mail.Error.MailServerEmpty
What it means
In Mail.processRow(), the SMTP server name is read from the incoming row at data.indexOfServer; if it is null or empty (Utils.isEmpty) the step throws KettleException 'Mail.Error.MailServerEmpty' because no SMTP host was supplied for sending.
Solutions
- Set a static SMTP server in the step dialog instead of reading it from the row, if it never varies per row.
- Ensure the server field is populated for every row — filter or default empty values upstream.
- If using a variable for the server field, define it (kettle.properties / transformation parameter).
- Verify the correct column is selected as the 'SMTP server' source field in the dialog.
Example fix
// before <server_field>smtp_host</server_field> <!-- column empty in data --> // after: either fill the column upstream or use a static server <server>smtp.example.com</server>
Defensive patterns
Strategy: validation
Validate before calling
// before the Mail step FilterRows: smtp_server IS NOT NULL AND LENGTH(TRIM(smtp_server)) > 0 // or set a constant if the server never varies per row
Try / catch
try {
mail.processRow();
} catch (KettleException e) {
if (e.getMessage().contains("MailServerEmpty")) {
logError("SMTP server missing in row or configuration");
}
throw e;
} Prevention
- Prefer a static SMTP server setting when it does not vary per row.
- Define SMTP host variables in kettle.properties so substitutions never resolve empty.
- Filter rows lacking a server value before the Mail step.
- Audit the server field mapping after upstream schema changes.
When it happens
Trigger: The Mail step is configured with the SMTP server taken from a field, and the current row's server field is empty/null at data.indexOfServer.
Common situations: Server column missing values in source data; wrong column mapped as the server field; variable-substituted server field resolves to empty when the variable is undefined; environment switch (no SMTP host recorded for this environment).
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Mail.Error.MailDestinationEmpty
- Mail.Exception.CouldnotFindServerField
- MAIL001
- JobGetMailsFromPOP.Error.AttachmentFolderEmpty
- JobGetMailsFromPOP.Error.MoveToIMAPFolderEmpty
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/db8bdb2354b0ac8c.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/mail/impl/src/main/java/org/pentaho/di/trans/steps/mail/Mail.java:158
// reply addresses
String mailReplyToAddresses = null;
if ( data.indexOfReplyToAddresses > -1 ) {
mailReplyToAddresses = data.previousRowMeta.getString( r, data.indexOfReplyToAddresses );
}
String contactPerson = null;
if ( data.indexOfContactPerson > -1 ) {
contactPerson = data.previousRowMeta.getString( r, data.indexOfContactPerson );
}
String contactPhone = null;
if ( data.indexOfContactPhone > -1 ) {
contactPhone = data.previousRowMeta.getString( r, data.indexOfContactPhone );
}
String serverName = data.previousRowMeta.getString( r, data.indexOfServer );
if ( Utils.isEmpty( serverName ) ) {
throw new KettleException( "Mail.Error.MailServerEmpty" );
}
int port = -1;
if ( data.indexOfPort > -1 ) {
port = Const.toInt( "" + data.previousRowMeta.getInteger( r, data.indexOfPort ), -1 );
}
String authUser = null;
if ( data.indexOfAuthenticationUser > -1 ) {
authUser = data.previousRowMeta.getString( r, data.indexOfAuthenticationUser );
}
String authPass = null;
if ( data.indexOfAuthenticationPass > -1 ) {
authPass = Utils.resolvePassword( getParentVariableSpace(), data.previousRowMeta.getString( r, data.indexOfAuthenticationPass ) );
}
String subject = null;
if ( data.indexOfSubject > -1 ) {
subject = data.previousRowMeta.getString( r, data.indexOfSubject );View on GitHub (pinned to f3058517a1)