{"record":{"id":"2bb86bab45b88989","repo":"pentaho/pentaho-kettle","slug":"mail-error-maildestinationempty","errorCode":null,"errorMessage":"Mail.Error.MailDestinationEmpty","messagePattern":"Mail\\.Error\\.MailDestinationEmpty","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"plugins/mail/impl/src/main/java/org/pentaho/di/trans/steps/mail/Mail.java","lineNumber":124,"sourceCode":"\n    if ( first ) {\n      first = false;\n\n      // get the RowMeta\n      data.previousRowMeta = getInputRowMeta().clone();\n\n      validateMetaFields( meta );\n\n      cacheFieldsPosition( meta, data );\n\n      checkEmbeddedImages( meta, data );\n    } // end if first\n\n    try {\n      // get values\n      String mailDestination = data.previousRowMeta.getString( r, data.indexOfDestination );\n      if ( Utils.isEmpty( mailDestination ) ) {\n        throw new KettleException( \"Mail.Error.MailDestinationEmpty\" );\n      }\n      String mailDestinationCc = null;\n      if ( data.indexOfDestinationCc > -1 ) {\n        mailDestinationCc = data.previousRowMeta.getString( r, data.indexOfDestinationCc );\n      }\n      String mailDestinationBCc = null;\n      if ( data.indexOfDestinationBCc > -1 ) {\n        mailDestinationBCc = data.previousRowMeta.getString( r, data.indexOfDestinationBCc );\n      }\n\n      String mailSenderName = null;\n      if ( data.indexOfSenderName > -1 ) {\n        mailSenderName = data.previousRowMeta.getString( r, data.indexOfSenderName );\n      }\n      String mailSenderAddress = data.previousRowMeta.getString( r, data.indexOfSenderAddress );\n\n      // reply addresses\n      String mailReplyToAddresses = null;","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/plugins/mail/impl/src/main/java/org/pentaho/di/trans/steps/mail/Mail.java#L106-L142","documentation":"In Mail.processRow(), the step reads the destination e-mail address from the incoming row at data.indexOfDestination. If the value is null or empty (Utils.isEmpty), it throws a KettleException with the 'Mail.Error.MailDestinationEmpty' message because an e-mail cannot be sent without a recipient.","triggerScenarios":"Executing the Mail step with 'To' taken from a field: the destination field exists but its value in the current row is empty/null — the row passes the field-existence check but the address column is blank.","commonSituations":"Upstream data has missing e-mail addresses (null contact column); a filter removed placeholder values; the wrong column is mapped as the destination field; test rows with empty addresses reach the step.","solutions":["Filter or conditionally skip rows with empty destination before the Mail step (Filter rows / Stream Lookup guard).","Map the correct column as the 'To' destination field in the step dialog.","Provide a fallback/default address via a 'Value Mapper', 'If field value is null' step, or coalesce logic upstream.","Handle the exception (or enable step error handling) to route bad rows to an error stream instead of failing the transformation."],"exampleFix":"// before: mail step processes every row\nMail -> (throws on empty address)\n// after: guard upstream\nFilter rows (destination IS NOT NULL AND destination <> '') -> Mail","handlingStrategy":"validation","validationCode":"// before the Mail step, filter empty destinations\nFilterRows: destination IS NOT NULL AND LENGTH(TRIM(destination)) > 0","typeGuard":null,"tryCatchPattern":"// step error handling: route rows that throw to an error stream\nstepMeta.setSupportsErrorHandling(true);\n// or catch in custom code:\ntry {\n  mail.processRow();\n} catch (KettleException e) {\n  if (e.getMessage().contains(\"MailDestinationEmpty\")) {\n    logError(\"Row has empty destination address: \" + e.getMessage());\n  }\n}","preventionTips":["Add a filter/null-guard step before any Mail step reading addresses from fields.","Cleanse source data: coalesce missing e-mails to a default or a dead-letter flow.","Enable error handling on the Mail step to divert bad rows instead of aborting.","Verify the destination field mapping after any upstream schema change."],"tags":["kettle","mail","validation","empty-field"],"backgroundTag":"empty-required-field","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}