PDA

View Full Version : سوال: مشكل در خواندن body در email



SReza1
دوشنبه 09 اسفند 1389, 12:16 عصر
سلام
من مشلكي روي خواندن emailهاي فارسي دارم. از دلفي 7 هم استفاده مي‌كنم. نحوه ارسال emailهاي فارسي با 1000 بدبختي و با استفاده از كامپوننتهاي tnt مشكلم حل شد. هر چند كه بايستي در مقصد كاربر دريافت كننده Encoding را انتخاب بكنه. راهي هم پيدا نكردم كه در سورس اينكارو بكنم و نياز نباشه كاربر اين كار رو بكنه.
اما مشكله اصلي خواندن متن فارسي است. در لاتين مشكل نداره و در فارسي حروف عجيب غريب ميزنه مثله اين :

ط³ظ„ط§ظ…
ط§ظٹظ† طھط³طھ ظ¾ط³طھ ط§ظ„ظƒطھط±ظˆظ†ظٹظƒظٹ ظپط§ط±ط³ظٹ ط§ط³طھ

ContetntTransfer هم برابر با quoted-printable و ContentType هم برابر با text/plain; charset=utf-8 است.
تنظيمات Regional option هم همش فارسي است. چه بايد بكنم؟ تابعي براي Convert اين حروف وجود داره و يا اينكه بايستي در نحوه خواندن email كار كنم.

vcldeveloper
دوشنبه 09 اسفند 1389, 14:43 عصر
قبلا به یکی از دوستان این جواب رو داده بودم...

علتش خودِ پروتکل SMTP هست. اون پروتکل ذاتا 7-بیتی هست، یعنی فقط داده های ASCII رو ارسال میکنه. برای اینکه داده یونیکد توسط اون ارسال کنید، دو راه دارید، یکی اینکه به SMTP بگید از 8-بیت برای ارسال استفاده کنه، و متن پیام را هم با UTF-8 اینکد کنید، یا اینکه متن پیام را با استفاده از Base64 اینکد کنید، و خصوصیت ContentTransferEncoding را روی base64 تنظیم کنید.


برای حالت اول، می تونید Charset مربوط به Message را روی UTF-8 تنظیم کنید. ContentTransferEncoding را هم روی 8bit تنظیم کنید، و در هنگام ذخیره متن نامه در خصوصیت Body، از تابع Utf8Encode برای تبدیل متن به UTF-8 استفاده کنید.


برای حالت دوم هم تا جایی که خاطرم هست، یک بار در سایت برنامه نویس نمونه کد گذاشتم.

SReza1
دوشنبه 09 اسفند 1389, 15:24 عصر
جناب كشاورز
ممنون از راهنمايييون ،
مشكله ارسال فقط الان در subject است كه البته با تغيير Encodimg در سيستم دريافت كننده حل مي‌شه (كه البته من دنبالشوم اتوماتيك بشه). راهي وجود داره براي اتوماتيك‌سازي؟

الان مشكله Body من ندارم . مشكله subject دارم.
و دوم اينكه من در هنگام دريافت متن فارسي چه كنم؟ چه body و چه Subject؟
كامپوننت tnt هم گذاشتم نشد. هنگام خوندن چه كار كنم؟
قبلا مطالبي در اين خصوص تو سايت برنامه نويس بود ولي كمكي نكرد.

اين كد Send است


var
FSMTP: TIdSMTP;
IdMsgSend: TIdMessage;
Stream: TMemoryStream;
Encoder: TIdEncoderMIME;
EncodedText: string;
begin
IdMsgSend := TIdMessage.Create(Self);
IdMsgSend.MessageParts.Clear;

Stream := TMemoryStream.Create;
Encoder := TIdEncoderMIME.Create(nil);
try
// Retrieve the message from a Unicode source
TntRichEdit1.Lines.SaveToStream(Stream);
// Encode the message
Stream.Position := 0;

EncodedText := Encoder.Encode(Stream);
finally
Encoder.Free;
Stream.Free;
end;

IdMsgSend.CharSet := 'UTF-8';
IdMsgSend.IsEncoded := True;
IdMsgSend.ContentType := 'text/html';
IdMsgSend.ContentTransferEncoding := 'base64';
IdMsgSend.Body.Text := EncodedText;
IdMsgSend.From.Text := edSnd.Text;
IdMsgSend.Recipients.EMailAddresses := EdtTO.Text;
IdMsgSend.Subject := edSubject.Text;
IdMsgSend.Priority := TIdMessagePriority(mpHighest);

try
FSMTP := TIdSMTP.Create(Self);
FSMTP.Username := edSnd.Text;
FSMTP.Password := edPassword.Text;
FSMTP.Host := edSMTP.Text;
FSMTP.Port := StrToInt(edPort.Text);
FSMTP.AuthenticationType := atLogin;
if not FSMTP.Connected then
FSMTP.Connect;

FSMTP.Send(IdMsgSend);
FSMTP.Disconnect;
MessageDlg('Ok', mtInformation, [mbok], 0);
except
on E: Exception do
MessageDlg(E.Message, mtError, [mbok], 0);
end;
FreeAndNil(FSMTP);
end;


و اينم كد Recmail

var
FMsgCount, intIndex: integer;
i :
integer;
POP :
TIdPOP3;
MessageText :
WideString;
Msg :
TIdMessage;
Encoder :
TIdEncoderMIME;
begin
POP := TIdPOP3.Create(Self);
Msg := TIdMessage.Create(Self);
try
if POP.Connected then
POP.Disconnect;
POP.Host := edPop.Text;
POP.Password := edPassword.Text;
POP.Port := 110;
POP.Username := edLogin.Text;
POP.Connect;
FMsgCount := POP.CheckMessages;
if FMsgCount > 0 then
begin
for intIndex := 1 to FMsgCount do
begin
try
Msg.Clear;
except
on Exception do
;
end;
end;

POP.Retrieve(intIndex, Msg);

MessageText := '';
edLettSubject.Text := Msg.Subject;

for i := 0 to Msg.MessageParts.Count - 1 do
begin
if (Msg.MessageParts.Items[i] is TIdText) then
begin
try
MessageText := TIdText(Msg.MessageParts.Items[i]).Body.Text;
except
on Exception do
end;
end
end;
Editor.Text := MessageText;
end;

try
POP.Disconnect;
except
on Exception do
POP.DisconnectSocket;
end;
except
on E: Exception do
Caption := E.Message;
end;
finally
Msg.Free;
Pop.Free;
end;
end;

vcldeveloper
دوشنبه 09 اسفند 1389, 23:53 عصر
سلام،

لطفا برای کدهایی که میزارید، حتما از تگ CODE یا تگ PASCAL استفاده کنید، تا کد قابل خواندن باشه. من کد شما را ویرایش کردم تا هم Indentation داشته باشه، هم از چپ به راست نمایش داده بشه، و هم Syntax Highlighting داشته باشه.

درباره کدتون، حتما به این نکته دقت داشته باشید که استفاده از try except های بی مورد باعث خواهد شد که اولا کارایی کدتان کاهش پیدا کنه، ثانیا بسیاری از خطاها در حین اجرای برنامه پنهان بمانند، و بعدا بدون اطلاع شما در سایر بخش های برنامه اخلال ایجاد کنند، و ثالثا، موجب اخلال در کار Indy بشند. Indy برای برخی از امور خودش از Exception استفاده میکنه. خفه کردن Exception ها به این شکلی که شما انجام دادید، میتونه در فعالیت نرمال Indy هم اخلال ایجاد کنه.

درباره Subject مطمئن نیستم. فکر می کنم قبلا در یک تاپیک دیگه ایی راه حلی براش ارائه کرده بودم. در هر حال، تست کنید، ببینید آیا با Encode کردن متن Subject با UTF-8 یا با Base64، مشکل تان برطرف میشه یا خیر؟

خوندن ایمیل UTF-8، با دلفی 7 که همه چیزش ANSI هست، گرفتاریش بیشتر هست. اگر با Base64 اینکد کرده باشید، مشکل خاصی نباید داشته باشید، چون خروجی Base64 به صورت ANSI هست، پس متن دریافتی رو می تونید بدون مشکل در یک متغیر از نوع string بریزید، اما از اونجایی که متن اینکد شده، برای رسیدن به متن فارسی باید یک بار اون متن با Base64 دیکد کنید. اگر تنظیمات مربوط به Non-Unicode applications ویندوز بر روی فارسی تنظیم باشه، باید بتونید متن فارسی رو درست نمایش بدید. البته اگر متن فارسی شما UTF-8 هست، باید یک بار دیگه هم دیکدش کنید، این بار از UTF-8 به ANSI. اگر درباره تنظیمات ویندوز مطمئن نیستید، ولی میخواید متن فارسی درست نمایش داده بشه، باید از یک کنترل یونیکد مثل کامپوننت های TNT برای نمایش استفاده کنید. در اون صورت، باید بعد از دیکد کردن Base64، اگر متن UTF-16 هست، خروجی رو در یک WideString بریزید. اگر متن UTF8 هست، باید اون رو در یک بافر موقت (مثلا MemoryStream) بریزید، سپس با یک تابع از UTF8 به UTF-16 تبدیلش کنید، و سپس خروجی را در یک WideString بریزید.

عمده این مشکلاتی که در کار با ایمیل های غیر انگلیسی باهاشون مواجه میشید، به خاطر کاستی های پروتکل SMTP هست، و عدم پشتیبانی اون از یونیکد هست، که باعث میشه نیاز به روش هایی برای اینکد کردن متن به ANSI و بالعکس داشته باشید.

SReza1
سه شنبه 10 اسفند 1389, 11:40 صبح
حاج علي جان . يه كم گيج شدم! ميشه يك كم با كد توضيح بديد
البته مشكل subject حل نشده.

تجلی
یک شنبه 02 بهمن 1390, 22:48 عصر
چرا من وقتی یه متنی رو که از یک memo اینکود کردم رو مجدد دیکود میکنم تا به متن اصلی برسم نمیتونم متن فارسی رو بدون تغییر در local language ویندوز ببینم . این راهنمایی ها رو هم انجام دادم ولی نشد که نشد به جاش علامت سوال نشون میده.
از دلفی xe هم استفاده میکنم.


procedure TForm1.Button2Click(Sender: TObject);
var input,output:TStringStream;
st:WideString;

begin
input:=nil;
output:=nil;
input:=TStringStream.Create();
output:=TStringStream.Create();
memo2.Lines.SaveToStream(input);
input.Position:=0;
decoder.DecodeBegin(output);
decoder.Decode(input);
decoder.DecodeEnd;
output.Position:=0 ;

st:=UTF8ToUTF16(output.DataString);