mazluta 1 Posted Sunday at 11:05 PM Is there anyone that tried to open mail online with attachment? 1. get AccessToken from Graph API with clientID, ApplicationID +++ (that work) 2. upload file to onedrive. (that work) 3. get sharelink. (that work) 4. open /me/message (that FAIL) 5. the subject will be empty, the body empty. 6. the user can add more files. 7. the user can add recipients, subject, body..... 8. click on send. i have mange to get the AccessToken. Upload the file to ondrive/temp folder get the sharelink but i can not draft the message. CHATGPT - professional - did not help. GIMINI - Advance - the same MICROSOFT - like to make living harder this is the log ============ CreateSharingLink - Response Status Code: 200 CreateSharingLink - Response Body: {"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.permission","id":"6977e500-5d45-47cc-82e8-d6ea3ceeef8d","roles":["read"],"shareId":"u!aHR0cHM6Ly9oYW5pYmFhbGNvaWwtbXkuc2hhcmVwb2ludC5jb20vOmI6L2cvcGVyc29uYWwvbWF6bHV0YV9oYW5pYmFhbF9jb19pbC9FVS1BSU1VOTU1UkJsX0RveDhrUlBUUUJGZDBXNmlOcVY3bEljQlVYcTMwME5R","hasPassword":false,"link":{"scope":"organization","type":"view","webUrl":"https://hanibaalcoil-my.sharepoint.com/:b:/g/personal/mazluta_hanibaal_co_il/EU-AIMU955RBl_Dox8kRPTQBFd0W6iNqV7lIcBUXq300NQ","preventsDownload":false}} CreateSharingLink - HTTP Protocol version Version: 2 CreateSharingLink - Result.webUrl = https://hanibaalcoil-my.sharepoint.com/:b:/g/personal/mazluta_hanibaal_co_il/EU-AIMU955RBl_Dox8kRPTQBFd0W6iNqV7lIcBUXq300NQ CreateSharingLink - Result.shareId = u!aHR0cHM6Ly9oYW5pYmFhbGNvaWwtbXkuc2hhcmVwb2ludC5jb20vOmI6L2cvcGVyc29uYWwvbWF6bHV0YV9oYW5pYmFhbF9jb19pbC9FVS1BSU1VOTU1UkJsX0RveDhrUlBUUUJGZDBXNmlOcVY3bEljQlVYcTMwME5R UploadAndOpenMailWithAttachment - Share URL created: https://hanibaalcoil-my.sharepoint.com/:b:/g/personal/mazluta_hanibaal_co_il/EU-AIMU955RBl_Dox8kRPTQBFd0W6iNqV7lIcBUXq300NQ UploadAndOpenMailWithAttachment - Share ID: u!aHR0cHM6Ly9oYW5pYmFhbGNvaWwtbXkuc2hhcmVwb2ludC5jb20vOmI6L2cvcGVyc29uYWwvbWF6bHV0YV9oYW5pYmFhbF9jb19pbC9FVS1BSU1VOTU1UkJsX0RveDhrUlBUUUJGZDBXNmlOcVY3bEljQlVYcTMwME5R UploadAndOpenMailWithAttachment - JSON Request: { "subject": "Document from DMS", "body": { "contentType": "HTML", "content": "Please review the attached file." }, "attachments": [ { "@odata.type": "#microsoft.graph.referenceAttachment", "name": "GettingStarted.pdf", "sourceUrl": "https://graph.microsoft.com/v1.0/shares/u!aHR0cHM6Ly9oYW5pYmFhbGNvaWwtbXkuc2hhcmVwb2ludC5jb20vOmI6L2cvcGVyc29uYWwvbWF6bHV0YV9oYW5pYmFhbF9jb19pbC9FVS1BSU1VOTU1UkJsX0RveDhrUlBUUUJGZDBXNmlOcVY3bEljQlVYcTMwME5R/root/content", "isInline": false } ]} UploadAndOpenMailWithAttachment - Create Draft Response Code: 400 UploadAndOpenMailWithAttachment - Create Draft Response Body: {"error":{"code":"UnableToDeserializePostBody","message":"were unable to deserialize "}} UploadAndOpenMailWithAttachment - Error creating draft. UploadAndOpenMailWithAttachment - Finished the main procedure : ============ procedure TMainForm.UploadAndOpenMailWithAttachment(const LocalFilePath: string); var HttpClient: THttpClient; OneDriveWebURL: string; AttachFileId: string; SharingLinkRec: TSharingLinkRec; DraftId: string; JSONRequestDraft: string; DraftResponse: IHTTPResponse; Headers: TNetHeaders; RequestContent: TStringStream; begin AppLog.Lines.Add(''); AppLog.Lines.Add('UploadAndOpenMailWithAttachment - Starting'); HttpClient := THttpClient.Create; try if UploadFileToOneDrive(LocalFilePath, OneDriveWebURL, AttachFileId) then begin AppLog.Lines.Add('UploadAndOpenMailWithAttachment - File uploaded to OneDrive'); SharingLinkRec := CreateSharingLink(AttachFileId); if SharingLinkRec.Found then begin AppLog.Lines.Add('UploadAndOpenMailWithAttachment - Share URL created: ' + SharingLinkRec.webUrl); AppLog.Lines.Add('UploadAndOpenMailWithAttachment - Share ID: ' + SharingLinkRec.shareId); JSONRequestDraft := '{' + ' "subject": "Document from DMS",' + ' "body": {' + ' "contentType": "HTML",' + ' "content": "Please review the attached file."' + ' },' + ' "attachments": [' + ' {' + ' "@odata.type": "#microsoft.graph.referenceAttachment",' + //' "name": "' + JsonEscape(j_FileName(LocalFilePath)) + '",' + ' "name": "' + j_FileName(LocalFilePath) + '",' + ' "sourceUrl": "https://graph.microsoft.com/v1.0/shares/' + SharingLinkRec.shareId + '/root/content",' + // **Corrected sourceUrl** ' "isInline": false' + ' }' + ' ]' + '}'; AppLog.Lines.Add('UploadAndOpenMailWithAttachment - JSON Request: ' + JSONRequestDraft); SetLength(Headers, 2); Headers[0].Name := 'Authorization'; Headers[0].Value := 'Bearer ' + FAccessToken; Headers[1].Name := 'Content-Type'; Headers[1].Value := 'application/json'; RequestContent := TStringStream.Create(JSONRequestDraft, TEncoding.UTF8); try DraftResponse := HttpClient.Post('https://graph.microsoft.com/v1.0/me/messages', RequestContent, nil, Headers); AppLog.Lines.Add('UploadAndOpenMailWithAttachment - Create Draft Response Code: ' + IntToStr(DraftResponse.StatusCode)); AppLog.Lines.Add('UploadAndOpenMailWithAttachment - Create Draft Response Body: ' + DraftResponse.ContentAsString); if (DraftResponse.StatusCode = 200) or (DraftResponse.StatusCode = 201) then begin // Extract the draft ID (you already have this function) DraftId := ExtractDraftIdFromResponse(DraftResponse.ContentAsString); AppLog.Lines.Add('UploadAndOpenMailWithAttachment - DraftId: ' + DraftId); // Open the draft in Outlook UniSession.AddJS(Format('window.open("https://outlook.office.com/mail/deeplink/compose?itemid=%s&exvsurl=1", "_blank");', [DraftId])); end else begin AppLog.Lines.Add('UploadAndOpenMailWithAttachment - Error creating draft.'); end; finally RequestContent.Free; end; end else begin AppLog.Lines.Add('UploadAndOpenMailWithAttachment - Failed to create shareable link.'); end; end else begin AppLog.Lines.Add('UploadAndOpenMailWithAttachment - Error uploading file to OneDrive.'); end; finally HttpClient.Free; end; AppLog.Lines.Add('UploadAndOpenMailWithAttachment - Finished'); AppLog.Lines.Add(''); end; this is the upload ============ function TMainForm.UploadFileToOneDrive(const LocalFilePath: string; out OneDriveWebURL : string; out AttachFileId : string) : Boolean; var HttpClient: THttpClient; FileStream: TFileStream; FileSize: Int64; UploadURL: string; Response: IHTTPResponse; Headers: TNetHeaders; OneDriveItemJSON: TJSONObject; Success: Boolean; begin Success := False; Result := False; AppLog.Lines.Add(''); AppLog.Lines.Add(''); OneDriveWebURL := ''; AttachFileId := ''; Try HttpClient := THttpClient.Create; try FileStream := TFileStream.Create(LocalFilePath, fmOpenRead or fmShareDenyNone); try FileSize := FileStream.Size; UploadURL := 'https://graph.microsoft.com/v1.0/me/drive/root:/Temp/' + ExtractFileName(LocalFilePath) + ':/content'; SetLength(Headers, 2); Headers[0].Name := 'Authorization'; Headers[0].Value := 'Bearer ' + FAccessToken; Headers[1].Name := 'Content-Type'; Headers[1].Value := 'application/octet-stream'; // Adjust if needed Response := HttpClient.Put(UploadURL, FileStream, nil, Headers); AppLog.Lines.Add('ResponseCode (Upload) := ' + IntToStr(Response.StatusCode)); AppLog.Lines.Add('ResponseBody (Upload) := ' + Response.ContentAsString); if (Response.StatusCode = 200) or (Response.StatusCode = 201) then begin OneDriveItemJSON := TJSONObject.ParseJSONValue(Response.ContentAsString) as TJSONObject; try if Assigned(OneDriveItemJSON) then begin OneDriveWebURL := OneDriveItemJSON.GetValue('webUrl').Value; AttachFileId := OneDriveItemJSON.GetValue('id').Value; AppLog.Lines.Add(''); AppLog.Lines.Add('OneDrive Web URL: ' + OneDriveWebURL); AppLog.Lines.Add(''); Success := True; end; finally OneDriveItemJSON.Free; end; end else begin AppLog.Lines.Add('Error uploading file to OneDrive. Status Code: ' + IntToStr(Response.StatusCode)); // Optionally log the full error response end; finally FileStream.Free; end; finally HttpClient.Free; end; Result := Success; AppLog.Lines.Add(''); AppLog.Lines.Add(''); Except; Result := False; End; end; this is the createShareLink Proc ==================== function TMainForm.CreateSharingLink(const FileId: string): TSharingLinkRec; var HttpClient: THttpClient; Payload: TStringStream; Response: IHTTPResponse; JsonObj: TJSONObject; begin Result.webUrl := ''; Result.shareId := ''; Result.Found := False; HttpClient := THttpClient.Create; try HttpClient.CustomHeaders['Authorization'] := 'Bearer ' + FAccessToken; HttpClient.ContentType := 'application/json'; AppLog.Lines.Add(''); AppLog.Lines.Add('HttpClient.CustomHeaders[Authorization] : ' + HttpClient.CustomHeaders['Authorization'] ); AppLog.Lines.Add('HttpClient.ToString : ' + HttpClient.ToString ); AppLog.Lines.Add(''); Payload := TStringStream.Create('{"type":"view","scope":"organization"}', TEncoding.UTF8); try Response := HttpClient.Post( 'https://graph.microsoft.com/v1.0/me/drive/items/' + FileId + '/createLink', Payload); AppLog.Lines.Add('CreateSharingLink - Response Status Code: ' + IntToStr(Response.StatusCode)); AppLog.Lines.Add('CreateSharingLink - Response Body: ' + Response.ContentAsString); AppLog.Lines.Add('CreateSharingLink - HTTP Protocol version Version: ' + VarToStr(Response.Version)); if (Response.StatusCode = 200) or (Response.StatusCode = 201) then begin JsonObj := TJSONObject.ParseJSONValue(Response.ContentAsString) as TJSONObject; try Result.webUrl := JsonObj.GetValue<TJSONObject>('link').GetValue<string>('webUrl'); Result.shareId := JsonObj.GetValue<string>('shareId'); finally JsonObj.Free; end; end else begin AppLog.Lines.Add('Failed to create sharing link: ' + Response.StatusText); AppLog.Lines.Add('Response Content: ' + Response.ContentAsString); end; finally Payload.Free; end; finally HttpClient.Free; end; AppLog.Lines.Add('CreateSharingLink - Result.webUrl = ' + Result.webUrl); AppLog.Lines.Add('CreateSharingLink - Result.shareId = ' + Result.shareId); Result.Found := (Trim(Result.webUrl) <> '') And (Trim(Result.shareId) <> ''); end; Share this post Link to post
Olli73 6 Posted Monday at 08:23 AM I have no experience with Microsoft API, but that looks to me that you do not need to create a sharelink first, instead you can directly enter the file or folder as sourceUrl: { "post": { "body": { "contentType": "text", "content": "I attached a reference to a file on OneDrive." }, "attachments": [{ "@odata.type": "#microsoft.graph.referenceAttachment", "name": "Personal pictures", "sourceUrl": "https://contoso.com/personal/mario_contoso_net/Documents/Pics", "providerType": "oneDriveConsumer", "permission": "Edit", "isFolder": "True" } ] } } Share this post Link to post
mazluta 1 Posted Monday at 12:31 PM (edited) thanks for you replay. this is not the solution. just to be clear. if i send the POST without the Attachment, the mail online is open. the problem is in the attachment array. i tried to send full path (from onedrive upload), fileID, linkID, webURL.... dont no what to try more. chatGPT and Gimini are looping over and over... the Microsoft stuff send you to articles that send you to more articles... Edited Monday at 12:31 PM by mazluta Share this post Link to post
Olli73 6 Posted Monday at 03:29 PM Have you also provided values for "providerType", "isFolder", ...? See my JSON above. Share this post Link to post
mvanrijnen 124 Posted Tuesday at 03:23 PM (edited) Also the method of inline sending the attachments is limited to a size ( i believe 3MB), my code (i'm in a hurry, so just a dump), you can get the idea how to from this. const CNST_RESOURCE_CREATEUPLOADSESSION = 'users/{sendasemailaddress}/messages/{messageid}/attachments/createUploadSession'; CNST_RESOURCE_CREATEDRAFTMESSAGE = 'users/{sendasemailaddress}/mailFolders/drafts/messages'; CNST_RESOURCE_SENDCREATEDRAFT = 'users/{sendasemailaddress}/messages/{messageid}/send'; function THSMSGraphAPI.FetchUploadURL(const AUploadSize: integer; const AFileName, AMessageID, AContentID, AContentType : string; const AIsInline : Boolean): string; var fuploadRequest : TRESTRequest; fuploadResponse : TMSGraphUploadSessionResponse; attreq : TMSGraphUploadSessionRequest; begin Result := ''; fuploadRequest := TRESTRequest.Create(nil); try fuploadRequest.Client := FRestClient; fuploadRequest.Method := TRESTRequestMethod.rmPOST; fuploadRequest.Resource := CNST_RESOURCE_CREATEUPLOADSESSION.Replace('{sendasemailaddress}', AccountEmailAddress, [rfReplaceAll, rfIgnoreCase]).Replace('{messageid}', AMessageID, [rfReplaceAll, rfIgnoreCase]); attreq.AttachmentItem.attachmentType := 'file'; attreq.AttachmentItem.name := ExtractFileName(AFileName); attreq.AttachmentItem.size := AUploadSize; attreq.AttachmentItem.isInline := (AIsInline) or (not AContentID.IsEmpty); attreq.AttachmentItem.contentID := AContentID; attreq.AttachmentItem.contentType := AContentType; fuploadRequest.AddBody(attreq.AsJSON, TRESTContentType.ctAPPLICATION_JSON); fuploadRequest.Execute(); if not LogInvalidResponse(fuploadRequest.Response, True, 'THSMSGraphAPI.FetchUploadURL') then begin fuploadResponse := TMSGraphUploadSessionResponse.FromJSON(fuploadRequest.Response.Content); Result := fuploadResponse.uploadUrl; end; finally fuploadRequest.Free; end; end; procedure THSMSGraphAPI.AddLargeAttachments(const AEmailMessageAttachments : TMvREMailAttachments; const AMessageID : string); function CreateSourceStream(const AAttachment : TMvREMailAttachment) : TStream; begin Result := nil; if AAttachment.IsFile then Result := TFileStream.Create(AAttachment.FileName, fmOpenRead or fmShareDenyWrite) else Result := TStringStream.Create(AAttachment.PayLoad); end; procedure UploadParts(const AUploadUrl : string; const ASourceStream : TStream; const AContentType : string); var memStream : TMemoryStream; fuploadPartRequest : TRESTRequest; hdr : string; size, done, todo : integer; begin fuploadPartRequest := TRESTRequest.Create(nil); memStream := TMemoryStream.Create; try fuploadPartRequest.URLAlreadyEncoded := True; fuploadPartRequest.Client := FUplClient; fuploadPartRequest.Method := TRESTRequestMethod.rmPUT; FUplClient.BaseURL := AUploadUrl; size := ASourceStream.Size; done := 0; todo := 0; ASourceStream.Position := 0; while (done<size) do begin todo := Min(CNST_MAXATTSIZE, size-done); memStream.Clear; ASourceStream.Position := done; memStream.CopyFrom(ASourceStream, todo); memStream.Position := 0; hdr := 'bytes ' + (done).ToString + '-' + (done+todo-1).ToString + '/' + size.ToString; fuploadPartRequest.ClearBody; fuploadPartRequest.Params.Clear; fuploadPartRequest.AddParameter('Content-Length', todo.ToString, TRESTRequestParameterKind.pkHTTPHEADER); fuploadPartRequest.AddParameter('Content-Range', hdr, TRESTRequestParameterKind.pkHTTPHEADER, [TRESTRequestParameterOption.poDoNotEncode]); if not AContentType.IsEmpty then fuploadPartRequest.AddParameter('Content-Type', AContentType, TRESTRequestParameterKind.pkHTTPHEADER, [TRESTRequestParameterOption.poDoNotEncode]); fuploadPartRequest.AddBody(memStream, TRESTContentType.ctAPPLICATION_OCTET_STREAM); ExecuteRequest(fuploadPartRequest, 'THSMSGraphAPI.AddLargeAttachments.UploadParts', True); LogInvalidResponse(fuploadPartRequest.Response, True, 'UploadParts'); done := done + todo; end; finally memStream.Free; fuploadPartRequest.Free; end; end; var att : TMvREMailAttachment; url : string; stream : TStream; begin for att in AEmailMessageAttachments do //if att.IsLargeAttachment then begin stream := CreateSourceStream(att); try // url := FetchUploadURL(stream.Size, att.FileName, AMessageID); url := FetchUploadURL(stream.Size, att.FileName, AMessageID, att.ContentID, att.ContentType, att.IsInline); UploadParts(url, stream, att.ContentType); finally stream.Free; end; end; end; function THSMSGraphAPI.SendEmailWithLargeAttachments(const AEmailMessage: TMvREMailMessage; AAPIMessage: TMSGraphSendEmailMessageBody): Boolean; function FetchImmutableID(const AID : string) : string; var req : TRESTRequest; request : TMSGraphTranslateExchangeIdsRequest; responseJSON, requestJSON : string; response : TMSGraphTranslateExchangeIdsResponse; begin Result := ''; req := TRESTRequest.Create(nil); try try req.Client := FRestClient; req.Method := TRESTRequestMethod.rmPOST; req.Resource := 'users/{sendasemailaddress}/translateExchangeIds'.Replace('{sendasemailaddress}', AccountEmailAddress, [rfReplaceAll, rfIgnoreCase]); SetLength(request.inputIds, 1); request.inputIds[0] := AID; request.targetIdType := 'restImmutableEntryId'; request.sourceIdType := 'restId'; TgoBsonSerializer.Serialize( request, requestJSON); req.AddBody(requestJSON, TRESTContentType.ctAPPLICATION_JSON); req.Execute(); responseJSON := req.Response.Content; TgoBsonSerializer.Deserialize(responseJSON, response); if length(response.value)>0 then Result := response.value[0].targetId; except on e: exception do begin Result := ''; raise Exception.CreateFmt('[THSMSGraphAPI.SendEmailWithLargeAttachments.FetchImmutableId]: %s\n%s', [e.ClassName, e.Message]); end; end; finally req.Free; end; end; function FetchMessagesForInternetMessageID(const AInternetMessageID : string) : TArray<string>; var req : TRESTRequest; request : TMSGraphTranslateExchangeIdsRequest; responseJSON, requestJSON : string; response : TMSGraphTranslateExchangeIdsResponse; begin SetLength(Result, 0); req := TRESTRequest.Create(nil); try try req.Client := FRestClient; req.Method := TRESTRequestMethod.rmGET; req.Resource := 'users/{sendasemailaddress}/messages?$filter=internetMessageId eq ''{internetmessageid}''' .Replace('{sendasemailaddress}', AccountEmailAddress, [rfReplaceAll, rfIgnoreCase]) .Replace('{internetmessageid}', TidUri.ParamsEncode(AInternetMessageID), [rfReplaceAll, rfIgnoreCase]); req.Execute(); except on e: exception do begin raise Exception.CreateFmt('[THSMSGraphAPI.SendEmailWithLargeAttachments.FetchMessagesForInternetMessageID]: %s\n%s', [e.ClassName, e.Message]); end; end; finally req.Free; end; end; var req1, req2 : TRESTRequest; draft : TMSGraphDraftResponse; draftremoved, step1done : boolean; removemsgid, immid : string; begin Result := False; immid := ''; removemsgid := ''; step1done := False; draftremoved := False; req1 := TRESTRequest.Create(nil); req2 := TRESTRequest.Create(nil); try try req1.Client := FRestClient; req1.Method := TRESTRequestMethod.rmPOST; req2.Client := FRestClient; req2.Method := TRESTRequestMethod.rmPOST; req1.Resource := CNST_RESOURCE_CREATEDRAFTMESSAGE.Replace('{sendasemailaddress}', AccountEmailAddress, [rfReplaceAll, rfIgnoreCase]); req1.AddBody(AAPIMessage.message.AsJson(), TRESTContentType.ctAPPLICATION_JSON); try req1.Execute(); except on e: exception do begin raise Exception.CreateFmt('[THSMSGraphAPI.SendEmailWithLargeAttachments.Req1]: %s\n%s', [e.ClassName, e.Message]); end; end; if not LogInvalidResponse(req1.Response, True, 'THSMSGraphAPI.SendEmailWithLargeAttachments.1') then begin draft := TMSGraphDraftResponse.FromJSON(req1.Response.Content); removemsgid := draft.id; step1done := IsValidResponse(req1.Response); if not (AEmailMessage.SaveOnSend) then begin immid := FetchImmutableID(draft.id); removemsgid := immid; end; {$ifdef debug} if not immid.IsEmpty then LogExInfo('ImmutableID: %s', [immid], 'THSMSGraphAPI.SendEmailWithLargeAttachments'); {$endif} //raise Exception.Create('TEST Error Message'); try AddLargeAttachments(AEmailMessage.Attachments, draft.id); except on e: exception do begin raise Exception.CreateFmt('[THSMSGraphAPI.SendEmailWithLargeAttachments.AddLargeAttachments]: %s\n%s', [e.ClassName, e.Message]); end; end; end; req2.Resource := CNST_RESOURCE_SENDCREATEDRAFT.Replace('{sendasemailaddress}', AccountEmailAddress, [rfReplaceAll, rfIgnoreCase]).Replace('{messageid}', draft.id, [rfReplaceAll, rfIgnoreCase]); try req2.Execute(); except on e: exception do begin raise Exception.CreateFmt('[THSMSGraphAPI.SendEmailWithLargeAttachments.Req2]: %s\n%s', [e.ClassName, e.Message]); end; end; if not LogInvalidResponse(req2.Response, True, 'SendWithLargeAttachments.2') then begin Result := True; if not (AEmailMessage.SaveOnSend) then begin if not immid.IsEmpty then draftremoved := TryRemoveEmailMessage(immid) else LogExWarn('Could not remove draft sendmessage because empty immutableid', 'THSMSGraphAPI.SendEmailWithLargeAttachments'); end; end; except on e: exception do begin Result := False; if (not draftremoved) and (step1done) and (not removemsgid.IsEmpty) then begin Sleep(1000); draftremoved := TryRemoveEmailMessage(removemsgid); if draftremoved then LogExWarn('Draft message with id: %s removed.', [removemsgid], 'THSMSGraphAPI.SendEmailWithLargeAttachments') else LogExError('Draft message with id: %s was not removed!', [removemsgid], 'THSMSGraphAPI.SendEmailWithLargeAttachments') end; raise; end; end; finally req2.Free; req1.Free; end; end; Edited Tuesday at 03:28 PM by mvanrijnen Share this post Link to post
mazluta 1 Posted 8 hours ago (edited) thanks to all how answer. On 4/22/2025 at 6:23 PM, mvanrijnen said: the attachments is limited to a size ( i believe 3MB), you right abut that. any way if the file is large the 5mb then send is with OneDrive reference. i also finish my TEST APP - Play with Microsoft 365. the application contain full demo. first you have to sign to 365. get clientID, tenantID, secretID +++ go to Azure and create new "Application". Create/Add Users. Set Desire Scop (Permission). the set all the code into the Main Form At The Const vars. compile and run. every one can do with it what ever he/she wants with no any responsibility of the author which is Hanibaal Information System. for start click on the "connect to 365" the application will get AccessToken. with this AccessToken you can : 1. list onedrive folders 2. open onedrive folder. 3. edit word/excel/powerpoint in online editor. in files/add-in i put some files that can be used as add-in. that let the user "click" on - "i finish, update file in my folder back" 4. upload file to one drive. 5. download from onedrive. 6. delete from onedrive 7. send file with outlook 365 online with attachment. if any one to continue and implement the work SharePoint, that will be nice the app is base on Delphi-UniGui. the Office365Integration.pas does all the job. if some one want to use it in Desktop Application, Replace : UniSession.AddJS('window.open("' + EditLink + '", "_blank");'); with : ShellExecute MzOffice365-U.zip Edited 8 hours ago by mazluta Share this post Link to post