Last active
October 26, 2025 18:30
-
-
Save Al-Muhandis/6c29bd118963604716955f2a88831038 to your computer and use it in GitHub Desktop.
CLI wrapper to send email via msmtp/sendemail (Linux specific)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| unit unix_sendmail; | |
| { smtp mailer via standard Unix sendmail support } | |
| {$mode ObjFPC}{$H+} | |
| interface | |
| uses | |
| Classes, SysUtils | |
| ; | |
| type | |
| TSendEmailResult = (serUnknown, serOk, serErrCldNtSndEml); | |
| { TSendMail } | |
| TSendMail = class | |
| private | |
| FAccount: String; | |
| FBody: String; | |
| FContentTransferEncoding: String; | |
| FContentType: String; | |
| FExecutable: String; | |
| FFrom: String; | |
| FOutputData: TStringList; | |
| FReplyToAddress: String; | |
| FToAddress: String; | |
| FSendResult: TSendEmailResult; | |
| FSubject: String; | |
| procedure ParseOutput; | |
| function EncodeHeader(const AValue: string): string; | |
| public | |
| constructor Create; | |
| destructor Destroy; override; | |
| function Send: Boolean; | |
| property From: String read FFrom write FFrom; | |
| property Account: String read FAccount write FAccount; | |
| property ToAddress: String read FToAddress write FToAddress; | |
| property ReplyToAddress: String read FReplyToAddress write FReplyToAddress; | |
| property Subject: String read FSubject write FSubject; | |
| property ContentType: String read FContentType write FContentType; | |
| property Body: String read FBody write FBody; | |
| property Executable: String read FExecutable write FExecutable; | |
| property SendResult: TSendEmailResult read FSendResult write FSendResult; | |
| property RawOutput: TStringList read FOutputData; | |
| end; | |
| procedure SendMail(const aToAddress, aSubject, aBody: string); | |
| implementation | |
| uses | |
| process | |
| ; | |
| const | |
| _CldNtSndEml='could not send mail '; | |
| procedure SendMail(const aToAddress, aSubject, aBody: string); | |
| var | |
| aSendMail: TSendMail; | |
| begin | |
| aSendMail:=TSendMail.Create; | |
| try | |
| aSendMail.ToAddress:=aToAddress; | |
| aSendMail.Subject:=aSubject; | |
| aSendMail.Body:=aBody; | |
| aSendMail.Send; | |
| finally | |
| aSendMail.Free; | |
| end; | |
| end; | |
| function ParseMSMTPOutput(const aOutput: String): TSendEmailResult; | |
| begin | |
| if aOutput.Contains(_CldNtSndEml) then | |
| Exit(serErrCldNtSndEml); | |
| Result:=serOk; | |
| end; | |
| { TSendMail } | |
| procedure TSendMail.ParseOutput; | |
| begin | |
| FSendResult:=ParseMSMTPOutput(FOutputData.Text); | |
| end; | |
| function TSendMail.EncodeHeader(const AValue: string): string; | |
| begin | |
| Result:=AValue; { #todo : May be encoding as an option? } | |
| end; | |
| constructor TSendMail.Create; | |
| begin | |
| FExecutable:='msmtp'; //'/usr/sbin/sendmail'; | |
| FOutputData:=TStringList.Create; | |
| FContentType:='text/plain; charset=UTF-8'; | |
| FContentTransferEncoding:='8bit'; | |
| end; | |
| destructor TSendMail.Destroy; | |
| begin | |
| FOutputData.Free; | |
| inherited Destroy; | |
| end; | |
| function TSendMail.Send: Boolean; | |
| var | |
| aMailProcess: TProcess; | |
| aMailData: TStringList; | |
| begin | |
| aMailData:=TStringList.Create; | |
| try | |
| aMailData.Add('MIME-Version: 1.0'); | |
| aMailData.Add('To: ' + FToAddress); | |
| aMailData.Add('Subject: ' + EncodeHeader(FSubject)); | |
| if not FReplyToAddress.IsEmpty then | |
| aMailData.Add('Reply-To: ' + FReplyToAddress); | |
| if not FFrom.IsEmpty then | |
| aMailData.Add('From: ' + FFrom); | |
| if not FContentType.IsEmpty then | |
| aMailData.Add('Content-Type: '+FContentType); | |
| if not FContentTransferEncoding.IsEmpty then | |
| aMailData.Add('Content-Transfer-Encoding: '+FContentTransferEncoding); | |
| aMailData.Add(EmptyStr); | |
| aMailData.Add(FBody); | |
| aMailProcess := TProcess.Create(nil); | |
| try | |
| aMailProcess.Executable := FExecutable; | |
| if not Account.IsEmpty then | |
| begin | |
| aMailProcess.Parameters.Add('-a'); | |
| aMailProcess.Parameters.Add(FAccount); | |
| end; | |
| aMailProcess.Parameters.Add('-t'); | |
| aMailProcess.Options := [poUsePipes, poStderrToOutPut]; | |
| aMailProcess.Execute; | |
| aMailData.SaveToStream(aMailProcess.Input); | |
| aMailProcess.CloseInput; | |
| FOutputData.LoadFromStream(aMailProcess.Output); | |
| ParseOutput; | |
| Result:=FSendResult=serOk; | |
| finally | |
| aMailProcess.Free; | |
| end; | |
| finally | |
| aMailData.Free; | |
| end; | |
| end; | |
| end. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment