Improving efficiency and flow by changing subroutine orders
1) What is this line supposed to do?

%comspec% /c exit %0%


I can almost guarantee it is not doing what you think. The most it can do is set the ERRORLEVEL. However, The EXIT command expects a numeric argument, but you pass %0%. The EXIT command returns 0 if it does not receive a numeric argument.

I doubt you have a variable with a name of "0", so the EXIT command sees a string literal value of %0%, which is non-numeric. It consequently returns 0 every time.

Your very next command (FINDSTR), is an external command, so it will set the ERRORLEVEL anyway. There is no need to initialize it.

2) It is generally a good idea to enclose SET assignments in quotes. This guards against poison characters, and inadvertent trailing spaces. (There are some exceptions, but it is a good rule of thumb).

3) It is generally a good idea to always enclose file paths in quotes if a portion is a variable. You never know if the variable may contain spaces or poison characters. The %TEMP% value normally does not have spaces, but it certainly could.

4) There is no need to delete "%temp%\rdcto.txt" when you immediately turn around and recreate it. You can simply redirect using overwrite mode (&gt;) instead of append mode (&gt;&gt;). This will guarantee you start out with a fresh file each time.

5) Why do you write the value of %MailDst% using a FOR statement? You can simply echo the value directly.

&gt;"%temp%\rdcto.txt" echo %MailDst%


6) You do not need to create an :end label and GOTO that label. Instead you can do either of the following: goto :eof or exit /b. They are identical, and neither form requires an explicitly declared label. The only difference is that exit /b can take an optional argument specifying the returned errorlevel.

7) You should encapsulate the logic for writing an email into a subroutine that accepts the variable portion as arguments. It reduces the amount of code, and eases maintenance.

8) I've simplified your ERRORLEVEL logic by using an extra variable to store the return code. I also make use of the conditional &amp;&amp; and || operators with FINDSTR - I find them to be more convenient then checking the ERRORLEVEL. But I didn't use them with WinSCP because the logic is a bit complex.

Note that if the last command within a &amp;&amp;( successCommands ) block raises an error, then it would cause the ||( errorCommands ) block to fire. That is why my :sendMail routine explicitly exits with a return code of 0 (success).

Using the above principles, I would write the code as follows:

SET "MailSrc=downloader@mydomain.com"
SET "MailSrcName=Automated FTP Process"

SET "MailDst=successful_code@mydomain.com"
SET "FailMailDst=failed_code@mydomain.com"

SET "OKMailSub=Files Have Been Moved"
SET "NoFileMailSub=Files Not Present - Maybe Next Time"
SET "FailMailSub=An Error Occurred!"

SET "LOG=WSCPLog.txt"

IF EXIST "%LOG%" DEL "%LOG%"
START /WAIT WinSCP.exe /console /script=WSCP-GetC.txt /log="%log%"
SET "RTN=%ERRORLEVEL%"
FINDSTR /C:"Test_File.ext: No such file or directory" "%LOG%" &amp;&amp; (
  CALL :sendMail "%MAILdST%" "%NoFileMailSub%"
) || (
  IF %RTN% EQU 0 (
    CALL :sendMail "%MAILdST%" "%OKMailSub%"
  ) ELSE (
    CALL :sendMail "%FailMailDst%" "%FailMailSub%"
  )
)
EXIT /B

:sendMail
&gt;"%temp%\rdcto.txt" ECHO %~1
"%~dp0sendmail.exe" /TO="%temp%\rdcto.txt" /FROM=%MailSrcName% ^&lt;%MailSrc%^&gt; /REF=%~2 /MESSAGE=%log% /HOST=mail.mydomian.com
EXIT /B 0




Other possible changes:

I didn't make any of the changes below because you said your code was working, and I don't know those programs enough to guarantee the changes are an improvement.

A) I don't see why you run WinSCP via START. I believe you could simply use:

WinSCP.exe /console /script=WSCP-GetC.txt /log=%log%


B) Your sendmail arguments look very suspicious to me. Normally values that contain spaces should be enclosed in quotes. Note that the :sendMail routine above preserves the lack of quotes by using %~1 and %~2 instead of %1 and %2.

C) I don't know WinSCP, but I suspect it will overwrite any existing log file, in which case you could remove the prior DEL command.