{"record":{"id":"10deba0bd1e4980c","repo":"pentaho/pentaho-kettle","slug":"mail001","errorCode":"MAIL001","errorMessage":"Mail.Error.General","messagePattern":"Mail\\.Error\\.General","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"plugins/mail/impl/src/main/java/org/pentaho/di/trans/steps/mail/Mail.java","lineNumber":199,"sourceCode":"        comment = data.previousRowMeta.getString( r, data.indexOfComment );\n      }\n\n      // send email...\n      sendMail( r, serverName, port, mailSenderAddress, mailSenderName, mailDestination, mailDestinationCc,\n        mailDestinationBCc, contactPerson, contactPhone, authUser, authPass, subject, comment, mailReplyToAddresses );\n\n      putRow( getInputRowMeta(), r );\n\n      if ( log.isRowLevel() ) {\n        logRowlevel( BaseMessages.getString( PKG, \"Mail.Log.LineNumber\", getLinesRead()\n          + \" : \" + getInputRowMeta().getString( r ) ) );\n      }\n    } catch ( Exception e ) {\n      if ( getStepMeta().isDoingErrorHandling() ) {\n        // Simply add this row to the error row\n        putError( getInputRowMeta(), r, 1, e.toString(), null, \"MAIL001\" );\n      } else {\n        throw new KettleException( BaseMessages.getString( PKG, \"Mail.Error.General\" ), e );\n      }\n    }\n\n    return true;\n  }\n\n  private void checkEmbeddedImages( MailMeta meta, MailData data ) {\n    if ( meta.getEmbeddedImages() != null && meta.getEmbeddedImages().length > 0 ) {\n      FileObject image = null;\n      data.embeddedMimePart = new HashSet<>();\n      try {\n        for ( int i = 0; i < meta.getEmbeddedImages().length; i++ ) {\n          String imageFile = environmentSubstitute( meta.getEmbeddedImages()[i] );\n          String contentID = environmentSubstitute( meta.getContentIds()[i] );\n          image = KettleVFS.getInstance( getTransMeta().getBowl() ).getFileObject( imageFile );\n\n          if ( image.exists() && image.getType() == FileType.FILE ) {\n            // Create part for the image","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/plugins/mail/impl/src/main/java/org/pentaho/di/trans/steps/mail/Mail.java#L181-L217","documentation":"Mail.Error.General is the generic failure message thrown when the Mail step fails during processRow and no error-handling (putError) is configured on the transformation. The original exception is wrapped in a KettleException as the cause. It signals any send-mail failure (SMTP errors, missing fields, connection problems) that was not routed to the error stream.","triggerScenarios":"processRow caught an Exception while processing a row (e.g. SMTP send failed, null field value, misconfigured mail settings) AND the step meta reports isDoingErrorHandling()==false, so the catch block throws KettleException('Mail.Error.General', e) instead of calling putError.","commonSituations":"Running a transformation without an error-handling step attached to the Mail step; SMTP host/port/credentials wrong; test harness (testSendMailWithPassword) executing the step directly where error handling is not set up; network unreachable to the mail server.","solutions":["Inspect the wrapped cause exception (getCause()) for the real SMTP or NPE message","Attach an error-handling step to the Mail step so failures go to the error stream instead of aborting","Verify SMTP host, port, authentication and use of authentication settings in the Mail step dialog","Test connectivity to the SMTP server from the machine running the transformation"],"exampleFix":"// before: no error handling, exception aborts the transformation\nmailStep.doingErrorHandling = false;\n// after: route failing rows to an error stream\nmailStep.doingErrorHandling = true; // configure error handling target step","handlingStrategy":"try-catch","validationCode":"// before running: verify SMTP reachability and config\nProperties props = System.getProperties();\nprops.put(\"mail.smtp.host\", smtpHost);\nprops.put(\"mail.smtp.port\", String.valueOf(smtpPort));\ntry (Transport ignored = null) {\n  Session s = Session.getInstance(props);\n  Transport t = s.getTransport(\"smtp\");\n  t.connect(smtpHost, user, password);\n  t.close();\n}","typeGuard":null,"tryCatchPattern":"try {\n  mailStep.processRow();\n} catch (KettleException e) {\n  Throwable root = e.getCause(); // inspect real SMTP error\n  logError(\"Mail step failed: \" + root.getMessage(), e);\n}","preventionTips":["Always attach an error-handling step so failures land on the error stream instead of aborting","Validate SMTP host/port/credentials in the step dialog before production runs","Log the wrapped cause, not just the generic message"],"tags":["kettle","smtp","mail","error-handling"],"backgroundTag":"http-request-failed","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"}