A close-range finish from Mattia Valoti and a stunning strike from Sergio Floccari gave SPAL a 2-0 lead before the break at the Paolo Mazza.
SPAL were down a man shortly before half-time, though, as Marco D'Alessandro was sent off late in the first half, but a sluggish Milan lacked a cutting edge in attack until Ibrahimovic came on as a substitute.
A composed finish from Rafael Leao pulled one back for Milan with 11 minutes to go before Vicari turned an Alexis Saelemaekers cross into his own net in added time.
AC Milan (@acmilan) July 1, 2020
SPAL moved ahead when Valoti turned the ball home via a deflection after a scramble in the six-yard box.
Milan lost Samu Castillejo to injury and were two down when Floccari struck a sweet 30-yard half-volley that left Gianluigi Donnarumma grasping at thin air.
Hakan Calhanoglu bundled home as Milan sought a way back into the game, only for VAR to deem Ante Rebic to be in an offside position.
The VAR was in action again before the break, upgrading D'Alessandro's yellow card to a red for a dangerous two-footed lunge on Theo Hernandez.
The introduction of Ibrahimovic in the 65th minute brought Milan renewed purpose and he headed over from a good position.
Leao pulled one back for Milan with a cool finish after a poor clearance by goalkeeper Karlo Letica.
Milan's push for an equaliser appeared as though it would be fruitless but SPAL's players then had their heads in their hands in the fourth minute of injury time when Saelemaekers' seemingly harmless delivery was miscued by Vicari.
What does it mean? Milan Europe hopes dented
SPAL remain seven points adrift of safety, and with nine matches of the season remaining the two points they dropped from a winning position here may prove costly.
At 38, the best days of SPAL's Floccari are well behind him but he provided a moment of breath-taking quality.
The journeyman forward showed brilliant technique as he caught Donnarumma off his line with a superb long-range goal. His side will need more moments like this if they are stay up.
Rebic rues misses
Rebic carried Milan's attacking threat for the majority of the game but the Croatia international was wasteful whenever he found himself in a good position.
He will have breathed a sigh of relief that his profligacy did not see the game end in defeat for the Rossoneri after the late drama.
Key Opta Facts:
- Milan have drawn a Serie A match having trailed by two goals for the first time since April 2017 (versus Inter).
- It was the first time the Rossoneri have conceded two goals in the opening 30 minutes of a Serie A match since May 2017.
- Milan have found the net in 11 successive Serie A matches for the first time since October 2018.
- Sergio Floccari has found the net for the 15th successive calendar year, with his first strike in the current Serie A.
- Alessio Romagnoli played his 150th Serie A match for Milan.