Home > database >  File format or file extension is not valid
File format or file extension is not valid

Time:10-16

Until recently I've been using Excel 2013 but I've now upgraded to office 365. The Excel file i'm referring to was built in 2013. I have a macro that will save the 'Report' tab and attach this to an email however the attachment returns the below error when attempting to open;

'Excel cannot open the file 'Document1.xlsm' because the file format or file extension is not valid. Verify that the file has not been corrupted and that the file extension matches the format of the file'

I've checked that both the original Excel file and attachment are the same file format. Below is the VBA - Any suggestions on what to try would be greatly appreciated :)

Sub EmailSelectedSheets()

Dim SourceWB As Workbook
Dim DestinWB As Workbook
Dim OutlookApp As Object
Dim OutlookMessage As Object
Dim TempFileName As Variant
Dim ExternalLinks As Variant
Dim TempFilePath As String
Dim FileExtStr As String
Dim DefaultName As String
Dim UserAnswer As Long
Dim x As Long

Dim Rng As Range, mystr As String

'Optimize Code
  Application.ScreenUpdating = False
  Application.EnableEvents = False
  Application.DisplayAlerts = False

'Copy only selected sheets into new workbook
  Set SourceWB = ActiveWorkbook
  Sheet5.Select
  SourceWB.Windows(1).SelectedSheets.Copy
  Set DestinWB = ActiveWorkbook


'Determine Temporary File Path
  TempFilePath = Environ$("temp") & "\"

'Determine Default File Name for InputBox

    TempFileName = "Test"
  If SourceWB.Saved Then
    DefaultName = Left(SourceWB.Name, InStrRev(SourceWB.Name, ".") - 1)
  Else
    DefaultName = SourceWB.Name
  End If

  
'Determine File Extension
  If SourceWB.Saved = True Then
    FileExtStr = "." & LCase(Right(SourceWB.Name, Len(SourceWB.Name) - InStrRev(SourceWB.Name, ".", , 1)))
  Else
    FileExtStr = ".xlsm"
  End If

'Break External Links
  ExternalLinks = DestinWB.LinkSources(Type:=xlLinkTypeExcelLinks)

    'Loop Through each External Link in ActiveWorkbook and Break it
      On Error Resume Next
        For x = 1 To UBound(ExternalLinks)
          DestinWB.BreakLink Name:=ExternalLinks(x), Type:=xlLinkTypeExcelLinks
        Next x
      On Error GoTo 0
      
'Save Temporary Workbook
  DestinWB.SaveCopyAs TempFilePath & TempFileName & FileExtStr

'Create Instance of Outlook
  On Error Resume Next
    Set OutlookApp = GetObject(Class:="Outlook.Application") 'Handles if Outlook is already open
  Err.Clear
    If OutlookApp Is Nothing Then Set OutlookApp = CreateObject(Class:="Outlook.Application") 'If not, open Outlook
    
    If Err.Number = 429 Then
      MsgBox "Outlook could not be found, aborting.", 16, "Outlook Not Found"
      GoTo ExitSub
    End If
  On Error GoTo 0

'Create a new email message
  Set OutlookMessage = OutlookApp.CreateItem(0)

'Create Outlook email with attachment

  On Error Resume Next
  
    Set Rng = Worksheets("Sheet4").Range("B7:B23")
    Set Rng = Worksheets("Sheet4").Range("B7:B23").Merge(True)
    mystr = Join(Application.Transpose(Rng.Value), ";")
  
    With OutlookMessage
     .SentOnBehalfOfName "[email protected]"
     .To = Sheet4.Range("B6").Text
     .CC = ""
     .BCC = ""
     .Subject = TempFileName
     .Body = "Please find attached the latest report." & vbNewLine & vbNewLine & "Kind regards"
     .Attachments.Add TempFilePath & TempFileName & FileExtStr
     .Display
    End With
  On Error GoTo 0

'Close & Delete the temporary file
  DestinWB.Close SaveChanges:=False
  Kill TempFilePath & TempFileName & FileExtStr

'Clear Memory
  Set OutlookMessage = Nothing
  Set OutlookApp = Nothing
  
'Optimize Code
ExitSub:
  Application.ScreenUpdating = True
  Application.EnableEvents = True
  Application.DisplayAlerts = True

End Sub

CodePudding user response:

The original file and the attachment don't have the same format (the problem has nothing to do with sending the file per mail).

The original file is a file containing Macros, file type is (most likely) xlOpenXMLWorkbookMacroEnabled (52), extension is xlsm. You copy one of the sheets (sheet5) into a new workbook. What Excel does when you use the copy method is to create a workbook in the default file format (you can set this in the Excel Options under "Save"). In most cases this is format xlOpenXMLWorkbook (51), that is a macro-free workbook, extension xlsx.

What you now do is you save this workbook using the SaveCopyAs method. You provide a filename with an extension xlsm, but this doesn't change the file format. So you still have a file that is a macro-free workbook, but with the extension of a macro-enabled workbook. So extension and file format doesn't fit, and therefore you will get the error message that you (or whoever receives the mail) see.

You can easily proof this by removing the kill command, go to your temp folder and try to open the file - you will get the very same error message. Now rename the file to .xlsx and voilà, you can open the file.

There are some issues with your code. I guess you should refactor the code and split it to at least 2 routines: One saving the sheet as workbook and one that sends the mail. With that, you can test your functionality much easier because saving and sending are two separate tasks.

You don't need to select a sheet when you want to copy it (you hardly ever need to select or activate anything at all), and you shouldn't access the sheet via the Window-property. Simply use ActiveWorkbook.sheets(5).Copy.

After copying the sheet, you created a new workbook - you just need to save it. Don't use SaveCopyAs for that, use SaveAs. There, you can specify a filetype, and Excel will happily save the file in the format you want (and convert if necessary).
If you insist, you could save the copy as Macro-enabled, but as you send the file via mail, macro-free is usually the better option. Just be aware that filetype and extension fit. Or omit the extension at all, it that case Excel will add it for you automatically.

I refactored your code, have a look

Sub EmailSelectedSheets()
    'Optimize Code
    Application.ScreenUpdating = False
    Application.EnableEvents = False
    Application.DisplayAlerts = False

    Dim tmpFileName As String
    tmpFileName = SaveSheetAsTempFile(ThisWorkbook.Sheets(1)) ' Or whatever you want to save...
    
    SendMail tmpFileName

    Kill tmpFileName
    
ExitSub:
    Application.ScreenUpdating = True
    Application.EnableEvents = True
    Application.DisplayAlerts = True
End Sub

Function SaveSheetAsTempFile(ws As Worksheet) As String
    Dim DestinWB As Workbook
    ws.Copy
    Set DestinWB = ActiveWorkbook
    
    ExternalLinks = DestinWB.LinkSources(Type:=xlLinkTypeExcelLinks)
    'Loop Through each External Link in ActiveWorkbook and Break it
    On Error Resume Next
        Dim x As Long
        For x = 1 To UBound(ExternalLinks)
            DestinWB.BreakLink Name:=ExternalLinks(x), Type:=xlLinkTypeExcelLinks
        Next x
    On Error GoTo 0
        
    Dim tmpFileName As String
    tmpFileName = Left(ws.Parent.Name, InStrRev(ws.Parent.Name, ".") - 1)
    tmpFileName = Environ$("temp") & "\" & tmpFileName & ".xlsx"
    
    DestinWB.SaveAs tmpFileName, xlOpenXMLWorkbook
    SaveSheetAsTempFile = tmpFileName

End Function

Sub SendMail(attachmentName As String)
    ' do your email sending stuff here...
    .Attachments.Add attachmentName 
End Sub
  • Related